【问题标题】:Confusion about ctor/dtor behavior with inherited classes关于 ctor/dtor 行为与继承类的混淆
【发布时间】:2020-04-21 12:11:16
【问题描述】:

直到今天,我都认为我对继承的理解比我显然理解的要好得多。此示例的目标是设计一个包含 n 个类(在本例中为 3 个)的框架,每个类在程序的生命周期中都应该唯一存在。第四个类的实现将包含全局 main 函数,它将负责为其他类处理内存。此外,我希望保护基类中的公共成员,以防止任何其他类调用它们。

目前,“Main”类中的继承以及每个基类中的“protected:”关键字都被注释掉了。它并不完全符合我的要求,但一切正常。构造函数被调用一次(按升序),每个函数都被调用,然后是析构函数。

我在这里的困惑实际上是双重的。如果取消注释 Main 类中的继承,代码会编译,但 new 每个 ctor/dtor 会被调用两次,首先是升序,然后是降序。我一直无法解释为什么会发生这种情况,但这似乎不正确。我见过的所有关于继承的解释都很模糊,也没有解释为什么会发生这种情况。

class Main //: public A, public B, public C

我的第二个困惑点是类的受保护成员。我认为如果我取消注释“受保护:”关键字,继续基类中的方法,我应该能够从继承的类中调用它们。据我了解,假设我只希望孩子拥有此功能,我什至应该能够将它们作为私有继承。唉,我只是收到有关受保护方法的错误消息。

我很清楚我的理解存在一些重大缺陷,但我一直在竭尽全力寻找解释,但没有运气。我真的可以对这里发生的事情提出一些建设性的见解,

谢谢,

#include <iostream>
#include <memory>
using namespace std;

class A
{
    public:
    A() { cout << "Ctor A\n";} 
    ~A() { cout << "Dtor A\n";} 

    //protected:
    void func() { cout << "Function A\n"; }
};

class B
{
    public:
    B() { cout << "Ctor B\n";}
    ~B() { cout << "Dtor B\n";} 

    //protected:
    void func() { cout << "Function B\n"; }
};

class C
{
    public:
    C() { cout << "Ctor C\n";} 
    ~C() { cout << "Dtor C\n";}

    //protected:
    void func() { cout << "Function C\n"; }
};

class Main //: public A, public B, public C
{
    public:
    Main(A *a, B *b, C *c);
    private:
    std::unique_ptr<A> mA;
    std::unique_ptr<B> mB;
    std::unique_ptr<C> mC;
};

Main::Main(A *a, B *b, C *c) : mA(a), mB(b), mC(c)
{
    mA->func();
    mB->func();
    mC->func();
}

int main()
{
    Main m(new A, new B, new C);
    return 0;
}

如果有人好奇,我一直在尝试使用 gcc v8.3 编译器在 ideone.com 上编译它。

【问题讨论】:

  • 这是否回答了您问题的第二部分stackoverflow.com/questions/16785069/…
  • 如果我正确理解你的问题,也是第一部分,是的,如果你取消公共注释,它会调用构造函数两次,因为在你的代码中 Main::Main(A *a, B *b, C *c) 调用构造函数 A::A()B::B(),@987654328 @ 是从派生类 Main 隐含的。
  • 确实如此。我想我理解抽象类应该在继承成员时引用它的逻辑,但这并不是那么直观。似乎应该在文档或教程中更好地解释这一点。
  • 您混淆了继承(is-a 关系)和组合(has-a 关系)。如果Main 继承自A,那么您就是在表达Main 是一个 A。如果你给Main一个A类型的成员(或std::unique_ptr),那么你就是在表达Main有一个A。您想要两者中的哪一个取决于您要为类提供的语义,但您可能不想要both。没有更多细节,很难说出你想要哪个。另见例如this question.

标签: c++ inheritance constructor protected


【解决方案1】:

如果取消注释 Main 类中的继承,代码会编译,但 new 每个 ctor/dtor 会被调用两次,首先是升序,然后是降序。我一直无法解释为什么会发生这种情况,但这似乎不正确。我见过的所有关于继承的解释都很模糊,也没有解释为什么会发生这种情况。

你有三个电话给new。然后构造一个Main,这需要构造一个A、一个B和一个C。由于Main 的实例ABC,因此必须调用这三个构造函数来构造这三种类型的有效实例。 p>

我认为如果我取消注释“受保护:”关键字,继续基类中的方法,我应该能够从继承的类中调用它们。

当然,但不是在甚至不是派生类型的类的任意实例上!你有:

mA->func();

这是在Main 类的成员函数中,但在不是Main 类实例的东西上运行。 Main 类作为 A 类的实例对自身具有特殊访问权限——它的内部接口可以将自身的 protected 函数用作 A 类的实例,仅此而已。

【讨论】:

  • 那么如果目标是创建 3 个堆分配对象,我将如何管理呢? A 是否已分配隐式声明堆栈?
  • @mreff555 您的工作方式是,当您调用new 时,您确实创建了三个堆分配对象。目前尚不清楚您想要做什么,但您可能希望您的基类只是一个接口,Main 支持所有接口。
  • 你是对的。我担心这些将是相当大的类,除非需要,否则我不希望单个类有多个对象。似乎这会降低程序的内存效率。
  • @mreff555 是否要在堆上分配三个对象?如果你只想分配一个,有办法做到这一点(转发构造函数),但你指出了相反的方向。
  • @mreff555 如果您使用接口类,它的大小实际上将为零,并且其构造函数将被优化。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-09
  • 2015-05-13
  • 1970-01-01
  • 1970-01-01
  • 2012-09-20
  • 2011-12-30
相关资源
最近更新 更多