gpt4 book ai didi

c++ - 子类化和添加数据成员

转载 作者:行者123 更新时间:2023-11-28 08:30:06 25 4
gpt4 key购买 nike

我的类层次结构如下所示:


class Critical
{
public:
Critical(int a, int b) : m_a(a), m_b(b) { }
virtual ~Critical() { }
int GetA() { return m_a; }
int GetB() { return m_b; }
void SetA(int a) { m_a = a; }
void SetB(int b) { m_b = b; }
protected:
int m_a;
int m_b;
};

class CriticalFlavor : public Critical
{
public:
CriticalFlavor(int a, int b, int flavor) : Critical(a, b), m_flavor(flavor) { }
virtual ~CriticalFlavor() { }
int GetFlavor() { return m_flavor; }
void SetFlavor(int flavor) { m_flavor = flavor; }
protected:
int m_flavor;
};

class CriticalTwist : public Critical
{
public:
CriticalTwist(int a, int b, int twist) : Critical(a, b), m_twist(twist) { }
virtual ~CriticalTwist() { }
int GetTwist() { return m_twist; }
void SetTwist(int twist) { m_twist = twist; }
protected:
int m_twist;
};

就设计而言,以上内容对我来说似乎不正确,最让我困扰的是事实上,添加成员变量似乎驱动了这些类的接口(interface)(执行上述操作的实际代码稍微复杂一些,但仍然采用相同的模式)。当需要另一个“关键”类时,它会激增,只是增加一些其他的属性(property)。这对你来说合适吗?我该如何重构这样的代码?一个想法是只有一组接口(interface)并在涉及基础对象时使用组合像下面这样:


class Critical
{
public:
virtual int GetA() = 0;
virtual int GetB() = 0;
virtual void SetA(int a) = 0;
virtual void SetB(int b) = 0;
};

class CriticalImpl : public Critical
{
public:
CriticalImpl(int a, int b) : m_a(a), m_b(b) { }
~CriticalImpl() { }
int GetA() { return m_a; }
int GetB() { return m_b; }
void SetA(int a) { m_a = a; }
void SetB(int b) { m_b = b; }
private:
int m_a;
int m_b;
};

class CriticalFlavor
{
public:
virtual int GetFlavor() = 0;
virtual void SetFlavor(int flavor) = 0;
};

class CriticalFlavorImpl : public Critical, public CriticalFlavor
{
public:
CriticalFlavorImpl(int a, int b, int flavor) : m_flavor(flavor), m_critical(new CriticalImpl(a, b)) { }
~CriticalFlavorImpl() { delete m_critical; }
int GetFlavor() { return m_flavor; }
void SetFlavor(int flavor) { m_flavor = flavor; }
int GetA() { return m_critical->GetA(); }
int GetB() { return m_critical->GetB(); }
void SetA(int a) { m_critical->SetA(a); }
void SetB(int b) { m_critical->SetB(b); }
private:
int m_flavor;
CriticalImpl* m_critical;
};

最佳答案

我的建议:找到与您一起工作且最熟悉这段代码的最有耐心的人,并向他们询问其中的一些问题。我假设您由于 IP 问题而没有发布更完整的示例。这使得很难提供好的建议。

根据您的第一个代码示例,我会说只使用具有公共(public)数据的结构,而不使用访问器。但如果我看到真正的代码,我可能会改变我的看法。

对于您的第二个代码示例:一个好处是您可以让另一个类依赖于 CriticalFlavor 而无需了解任何关于 Critical 的内容(可用于实现类似 Bridge 的东西模式,例如)。但是,如果该潜在好处在您的情况下不是实际好处,那么它只会使您的代码变得不必要地复杂和 YAGNI(可能)。


审稿人的意见:

base classes should be abstract

我会说,“基类通常应该至少有一个虚拟方法,而不是析构函数”。如果不是,那么它只是一种在其他类之间共享公共(public)代码或数据的方法;尝试使用合成。

大多数时候,至少有一个虚拟方法是纯虚拟的,所以基类是抽象的。但有时每个虚拟方法都有一个很好的默认实现,子类将挑选并选择要覆盖的。在这种情况下,使基类构造函数 protected 以防止基类的实例化。

protected members are not advisable in base classes

...而且它们在非基类中完全没有意义,所以这条建议基本上是说永远不要使用它们。

何时 protected 成员变量是可取的?很少。您的代码示例不够真实,无法确定您要做什么或如何最好地编写它。成员受到保护,但有公共(public) getter/setter,因此它们本质上是公共(public)的。

design by interface

不要被这个冲昏了头脑,否则您可能会为了一个非常简单的任务而得到一个非常复杂的设计。在有意义的地方使用接口(interface)。如果没有看到一些使用 Critical 及其子类的“调用代码”,很难判断它们是否有意义。谁调用了 GetFlavorGetTwist

调用代码是只通过Critical接口(interface)与Critical子类交互,还是调用代码知 Prop 体的子类并调用具体的子类方法?您是否已将接口(interface)方法添加到 Critical 以提供对仅存在于某些子类中的数据/功能的访问?那可能是难闻的气味。


您的评论:

the addition of member variables seems to drive the interface of these classes

让我想起了 C++ Coding Standards 中的一个项目 (Sutter/Alexandrescu):“清楚你在写什么样的类”。抱歉,没有关于该项目的在线引用(购买这本书)。


我还建议您诚实地评估您和审稿人的技能水平。您的审阅者是经验丰富的 C++ 开发人员,他们真的知道他们在说什么(如果是,请听好!),或者他们刚从 Code Review 101 回来并且知道说诸如“公共(public)数据不好”和“析构函数应该始终是虚拟的”之类的话“?如果是后者,希望您可以通过说“这通常是个好建议,但不适用于这种情况,因为 XYZ”来回应评论意见。

关于c++ - 子类化和添加数据成员,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2532454/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com