C++ 中的继承:在父子类中定义变量

Posted

技术标签:

【中文标题】C++ 中的继承:在父子类中定义变量【英文标题】:Inheritance in C++: define variables in parent-child classes 【发布时间】:2019-05-03 11:47:46 【问题描述】:

问题

我正在寻找在父子类中定义变量的最佳方法,以便通过指向其父类的指针调用。 这是协议代码:

class Base 
    public:
        virtual void function() = 0;
;

class A : public Base 
public:
    int a, b;
    A(int a_, int b_) : a(a_), b(b_) ;
    void function()  // do something.. 
;

class B : public Base 
public:
    int a, b;
    B(int a_, int b_) : a(a_), b(b_) ;
    void function()  // do something.. 
;

Base* elements[2] = 
    new A(1,2),
    new B(3,4)
;

由于我在两个构造函数中都定义了a, b,我可以在抽象类Base 中定义它们。这样代码应该更高效、更干净。这种做法正确吗?我应该如何定义它们?

可能的解决方案

我想到的解决方案是实现一个函数,例如返回 a,如下所示:

class Base 
    public:
        virtual int return_a() = 0;
;

class A : public Base 
    public:
        int a, b;
        A(int a_, int b_) : a(a_), b(b_) ;
        int return_a() 
        return a;
        
;

int main()
    int a = elements[0]->return_a();

这可行,但我确信这不是一种有效的方法。在抽象类中定义a, b 更好吗?谢谢

【问题讨论】:

如果Base所有 个子级具有这些ab 成员,那么在Base 类中定义它们似乎是一个自然的解决方案。如果只有 一些 孩子使用 ab,那么您可以添加一个中间类,例如struct SubBase : public Base int a; int b; ; 然后让你的 AB 类继承自该类。 由于您显示的所有成员都是公开的,因此您可以改用struct(与class 相同,但默认可见性为public 而不是private)。如果ab 成员是公开的,则您不需要为它们提供任何“getter”函数。 公共派生方法可以直接访问公共 Base 属性。不需要'Base::return_x()'。 【参考方案1】:

这种做法正确吗?

我认为这正在变成基于意见的问答。如果您的所有派生类都必须包含成员ab那么在我看来,它们应该是基类的一部分。这样,您可以保证您的所有派生类都将包含成员 ab,并且您(或其他人)不会冒忘记包含它们的风险。此外,通过在基类中包含成员,您不必在每个派生类中都包含它们,从而节省了内存。 C++ 的virtual 为您提供了完成多态性所需的所有工具,这就是您创建Base * 数组时发生的情况。

我还建议您将关键字override 用于派生类中被覆盖的虚函数,将关键字final 用于不打算成为基类的派生类。您可以从 Scott Meyers Modern C++ 一书中了解使用这些关键字的好处。

struct Base

    int a, b;

    Base(int a_, int b_) : a(a_) , b(b_)
    ;

    virtual void function() = 0;
;

struct A : Base // A can be a base class of another class.

    A(int a_, int b_) : Base(a_,b_)
    ;

    void funtion() // this will compile, but it's not going to override the Base::function()
    ;
;

struct B final : Base // B can never become a base class.

    B(int a_, int b_) : Base(a_,b_)
    ;

    void funtion() override // this won't compile because override will see that we mis-spelled function() 
    ;
;

但是,没有 C++ 规则禁止您在所有派生类中包含成员。

另外,如果您的所有成员都是public,那么您可以使用struct 来避免在类和继承方法中键入public

struct Base

    // all members are public
;

struct Derived : Base // public inheritance by default.

    // all members are public
;

【讨论】:

感谢您的完整回答。在这种情况下,我想知道考虑到效率的解决方案(正如您所说,您的解决方案可以节省内存),但是如果我想问一个基于意见的问题,我可以在哪里做呢? @maurocomi:没问题!同样,这是一个灰色地带。您的 OP 中的代码运行良好。没有错误,也没有包含非法指令。这纯粹是一个效率问题。然而,效率可能会因软件的需求而异,因此没有一种正确的解决方案。这就是将您的问题变成基于意见的问答的原因。但是话又说回来,我认为您的问题对 SO 有效,因为必须考虑 IS-A、HAS-A、动态多态性等之间的差异。也许code-review 下次更适合。【参考方案2】:

这有点基于意见,但这是我根据您发布的代码的想法。

由于您已将Base(所有类都派生自该类)设为抽象类,因此您似乎想将其用作接口。

在这种情况下,最好区分接口继承和实现继承。让Base 没有任何数据,这意味着它不需要任何构造函数。

这是 Bjarne Stroustrup 给出的编码指南之一,标题为:When designing a class hierarchy, distinguish between implementation inheritance and interface inheritance

给出的原因是:

接口中的实现细节使接口变得脆弱;也就是说,使其用户很容易在实现更改后不得不重新编译。基类中的数据会增加实现基类的复杂性,并可能导致代码复制。

请注意,如果派生类中的数据为 public,则不需要 getter 或 setter。

【讨论】:

以上是关于C++ 中的继承:在父子类中定义变量的主要内容,如果未能解决你的问题,请参考以下文章

继承类中的c ++成员变量类型覆盖

在c++中的继承,如何在子类中重载成员函数

JAVA-初步认识-第八章-继承-子父类中成员变量的特点

深入浅出之C++中的继承

C++基础6 继承 类型兼容 satatic 多继承 虚继承 多态 案例 虚析构函数 重载重写重定义

C++继承 上篇