【问题标题】:Inheritance in C++: define variables in parent-child classesC++ 中的继承:在父子类中定义变量
【发布时间】: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()'。

标签: c++ class variables inheritance parent-child


【解决方案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。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-03-03
    • 2020-06-06
    • 2023-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-27
    相关资源
    最近更新 更多