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

标签 c++ class

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


    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/

相关文章:

c++ - : Expected constructor, 析构函数错误,或者 '<' token 之前的类型转换

c++ - 实现类似的类

Python:变量、继承和默认参数

android - 另一个 AsyncTask 问题 - 内部类看不到 doInBackground 方法

java - 如何在 Android exoplayer 中播放原始 NAL 单元?

python - 我无法使用 ctypes 访问 C++ 类属性

c++ - 我的 OpenGL C++ Eclipse 项目突然停止识别 glMatrixMode(GL_MODELVIEW)

c++ - Qt 还是 Symbian C++?

c# - c# - 如何让一个类对象存储另一个类对象?

php - 在声明之前使用 php 类