C ++构造/析构继承C ++构造/析构继承(C++ Constructor/Destructor

2019-05-13 00:11发布

编辑:答案汇总

在下文中,B是A的子类

这是术语的问题; 构建函数和dtors 继承,在这个意义上,B的构造函数/析构函数不会从A的接口借用。 一类至少有一个构造函数,只能有一个析构函数。

  • 构造函数
    • B不继承从A构造;
    • 除非B的构造函数调用明确地A的男星之一 ,从A默认的构造函数都会被自动B的构造函数体(想法是一个需要被创建B之前被初始化) 之前调用。
  • 析构函数
    • B不继承的析构函数;
    • 退出 ,B的析构函数会自动调用的析构函数。

致谢:我要感谢特别奥里查尔斯沃思和科斯对自己的答案,我设置科斯的答案,作为解决办法,因为这是我理解的最好的一个。


原帖

当你搜索“C ++的析构函数继承网站:stackoverflow.com”在谷歌,你现在找到以下职位:

  1. 构造函数和析构函数继承 :两个用户用30K +口碑说,这是遗传的,这不是
  2. 是虚拟的析构函数继承? :这里没有提到将指向析构函数没有被继承
  3. 析构函数和继承在C ++? :这些评论似乎表明析构函数继承

Q1:我也是从实践中知道的是,你不能用相同的原型比它的父类的构造没有明确地定义为派生类的构造函数初始化派生类对象,是正确的?


尽管这是从析构函数似乎继承了职位相当清楚的,我还在的事实,用32K的口碑,用户会说,它不是不解。 我写的应该澄清每个人的心中一个小例子:

#include <cstdio>

/******************************/

// Base class
struct A
{
    A() { printf( "\tInstance counter = %d (ctor)\n", ++instance_counter ); }
    ~A() { printf( "\tInstance counter = %d (dtor)\n", --instance_counter ); }

    static int instance_counter;
};

// Inherited class with default ctor/dtor
class B : public A {};

// Inherited class with defined ctor/dtor
struct C : public A
{
    C() { printf("\tC says hi!\n"); }
    ~C() { printf("\tC says bye!\n"); }
};

/******************************/

// Initialize counter
int A::instance_counter = 0;

/******************************/

// A few tests
int main()
{
    printf("Create A\n"); A a;
    printf("Delete A\n"); a.~A();

    printf("Create B\n"); B b;
    printf("Delete B\n"); b.~B();

    printf("Create new B stored as A*\n"); A *a_ptr = new B();
    printf("Delete previous pointer\n"); delete a_ptr;

    printf("Create C\n"); C c;
    printf("Delete C\n"); c.~C();

}

这里是输出(编译克++ 4.4.3):

Create A
    Instance counter = 1 (ctor)
Delete A
    Instance counter = 0 (dtor)
Create B
    Instance counter = 1 (ctor)
Delete B
    Instance counter = 0 (dtor)
Create new B stored as A*
    Instance counter = 1 (ctor)
Delete previous pointer
    Instance counter = 0 (dtor)
Create C
    Instance counter = 1 (ctor)
    C says hi!
Delete C
    C says bye!
    Instance counter = 0 (dtor)  // We exit main() now
    C says bye! 
    Instance counter = -1 (dtor)
    Instance counter = -2 (dtor)
    Instance counter = -3 (dtor)

Q2:任何人可以谁认为它是不能继承的,请解释一下吗?

Q3:所以,当你调用与输入的子类的构造会发生什么? 被称为以及超类的“空构造函数”?

Answer 1:

术语,术语...

OK,我们怎么通过“foo是继承了”是什么意思? 我们的意思是,如果类的对象, AFoo在它的界面,那么该类的对象B这是一个子类, A也有Foo在其接口。

  • 构造函数不是对象的接口的一部分。 他们直接属于类。 类AB可提供完全不同的集的构造函数。 没有“被继承”在这里。

    实现细节:每个B的构造函数调用一些A的构造函数)。

  • 析构函数确实是每个对象的接口的一部分,由于对象的用户是(即,直接与负责调用它们delete通过使对象超出范围或间接地)。 每个对象都只有一个析构函数 :自己的析构函数,这可能任选一个虚拟的。 它始终是自己的,并且它不是继承。

    (实现细节:B的析构函数调用A的析构函数)。

所以:有基类和派生构造函数和析构函数之间的连接,但它不喜欢“他们是继承”。

我希望这回答了你的想法。



Answer 2:

Q1:我也是从实践中知道的是,你不能用相同的原型比它的父类的构造没有显式定义派生类的构造函数初始化派生类对象,是正确的?

除了你已经定义的超类中的默认构造函数的简单的情况,是的,你是正确的。


Q2:任何人可以谁认为它是不能继承的,请解释一下吗?

这可能是术语的定义问题。 虽然很明显,虚析构函数存在,“预期”的工作中,我们看到在C ++标准([class.virtual]):

尽管析构函数不能被继承 ,在派生类中的析构函数覆盖声明为虚基类的析构函数

(重点煤矿)


Q3:所以,当你调用与输入的子类的构造会发生什么? 被称为以及超类的“空构造函数”?

如果不明确地调用一个特定的超类构造函数,那么默认的超类构造函数将被调用(假设它是可见的)。



Answer 3:

析构函数不能被继承。 如果一个类没有定义,编译器生成一个。 对于琐碎的案件析构函数只是调用基类的析构函数,而且往往这意味着有它的析构函数没有明确的代码(模仿继承)。 但是,如果一个类有析构函数的成员,生成的析构函数调用基类的析构函数之前呼吁成员析构函数。 在这个时候,一个继承的功能不会做。



Answer 4:

继承是什么:重用并没有修改它们扩展现有的类,从而产生它们之间的层次关系的机制。

继承是几乎像嵌入对象为一类。

当类在继承一个基类然后基类的构造函数被调用第一然后派生类的,和析构函数的呼叫是按相反的顺序。

那么,为什么基类构造函数被调用(称为不继承可以是与参数/默认值):以保证执行派生类的构造时的基类被适当地构造。

现在,调用析构函数的(主叫不能继承):当基对象走出的范围,然后调用析构函数在其own.so有析构函数的继承NP问题。

现在您的问题:

ANS 1 -是的,你是第一个问题是正确的。
答2 -所以析构函数对象的范围熄灭后调用不继承。
&ANS 3 -如果在派生类中你给带参数则只有构造函数被调用的号召,与它没有其他的构造函数被调用。
没有一点issuse的同一对象的2构造函数被调用的对象创建,作为构造被称为在创建一个对象。 它准备新的对象为use.so不存在与不同的构造制备两倍的对象的逻辑。



Answer 5:

从技术上讲,析构函数被继承。 但在正常情况下,析构函数继承不直接用于派生类; 他们援引因为派生类的析构函数本身为了破坏自己的“基类子对象”的范围内破坏较大的对象步骤调用它们。 而在不寻常的情况下,您就直接使用基类的析构函数派生类对象上,这是很难避免未定义行为。

本实施例中从C ++标准(12.4p12)来直。

struct B {
  virtual ~B() { }
};
struct D : B {
  ~D() { }
};

D D_object;
typedef B B_alias;
B* B_ptr = &D_object;

void f() {
  D_object.B::~B();              // calls B's destructor
  B_ptr->~B();                   // calls D's destructor
  B_ptr->~B_alias();             // calls D's destructor
  B_ptr->B_alias::~B();          // calls B's destructor
  B_ptr->B_alias::~B_alias();    // calls B's destructor
}

如果~B不是的一个继承的成员D ,在第一语句f将形成不良。 由于它是,它是合法的C ++,虽然极其危险的。



Answer 6:

在你的榜样,你是显式调用析构函数。 这是合法的(很明显,因为它编译和运行),但几乎总是不正确。

对于创建动态分配的对象new ,当反对与删除析构函数将运行delete

对于静态分配的对象,这是通过声明一个函数的范围内的对象简单地创建,当对象的范围消失析构函数运行。 也就是说,当main()退出时,对象的析构函数将被运行。 但是,你已经通过手动调用它们运行这些对象的析构函数! 这就是为什么你的榜样的输出显示计数下降到-3 ...你已经运行的析构函数ab ,和c两次。

下面是相同的代码,注释显示时的析构函数会被自动运行:

int main()
{
    printf("Create A\n"); A a;
    printf("Delete A\n"); a.~A();

    printf("Create B\n"); B b;
    printf("Delete B\n"); b.~B();

    printf("Create new B stored as A*\n"); A *a_ptr = new B();
    printf("Delete previous pointer\n");
    delete a_ptr;   // Implicitly calls destructor for a_ptr.  a_ptr is class B,
       // so it would call a_ptr->~B() if it existed. Because B is an A, after
       // its destructor is called, it calls the superclass's destructor,
       // a_ptr->~A().

    printf("Create C\n"); C c;
    printf("Delete C\n"); c.~C();
}
// Function exits here at the close brace, so anything declared in its scope is
// deallocated from the stack and their destructors run.
// First `c` is destroyed, which calls c.~C(), then because C is a subclass of A
// calls c.~B() (which doesn't exist, so a blank implementation is used), then
// because B is a subclass of A calls c.~A().  This decrements the counter, but
// the count is wrong because you already manually called c.~C(), which you
// ordinarily shouldn't have done.
// Then `b` is destroyed, in a similar manner.  Now the count is off by 2,
// because you had already called b.~B().
// Lastly `a` is destroyed, just as above.  And again, because you had already
// called a.~A(), the count is now off by 3.


Answer 7:

I would want to express my thoughts. Creating any object is done in two stages:

1.分配的存储器的对象区域。

  1. 初始化的内存此区域。

    对象的构造是类的功能(方法)(对于此目的),初始化自动分配的存储区域和调用。 在继承被嵌入一个类的目的是其它类的对象。 没有与poiners“这个”,“下盖”剧。 在“本”是隐式传递给类的方法。

    当代码“B B”是做什么正在发生的事情。 首先的存储器的区域被分配给对象b。 B类有自己默认的构造函数B(),它是自动调用初始化这个memeory。 B()因此堆栈帧被用于工作一个创建的函数。 这种构造B(含蓄)的地址。 但是A的对象必须嵌入到对象b。 A的对象没有名称。 B的构造函数知道A的NONAME嵌入的对象也必须被创建(因此编译的C ++作品)。 因此类A的用于初始化类A的NONAME embadded对象的构造被称为在B的构造函数的新的堆栈帧称为和NONAME对象被初始化。 在此之后,堆栈帧被关闭,我们的B类的对象B已经完成。 我认为B中的地址和NONAME对象不谋而合。

    析构函数类的过的方法。 当我们调用〜B()在B不被破坏。 析构函数是avtomatically调用的对象被破坏时的功能。 不过,这并不意味着,当我们调用析构函数的对象必须被销毁。 如果B的析构函数被调用时,针对一个创建的堆栈帧。 B的默认desructor知道类A的NONAME嵌入对象(因此编译的C ++作品)。 因此,destructore调用A的析构函数



文章来源: C++ Constructor/Destructor inheritance