C++ C++;构造函数/析构函数继承
编辑:答案摘要 在下文中,B是a的一个子类 这是一个术语问题;ctor和dtor不是继承的,因为B的ctor/dtor不会从A的接口借用。一个类至少有一个构造函数,并且正好有一个析构函数C++ C++;构造函数/析构函数继承,c++,inheritance,constructor,destructor,C++,Inheritance,Constructor,Destructor,编辑:答案摘要 在下文中,B是a的一个子类 这是一个术语问题;ctor和dtor不是继承的,因为B的ctor/dtor不会从A的接口借用。一个类至少有一个构造函数,并且正好有一个析构函数 构造函数: B不从A继承构造函数 除非B的ctor显式调用A的某个ctor,否则A的默认ctor将在B的ctor主体之前自动调用(其思想是A需要在创建B之前初始化) 析构函数: B不继承A的dtor 退出后,B的析构函数将自动调用A的析构函数 致谢: 我要特别感谢奥利·查尔斯沃思和科斯的回答,我把科
- 构造函数:
- B不从A继承构造函数李>
- 除非B的ctor显式调用A的某个ctor,否则A的默认ctor将在B的ctor主体之前自动调用(其思想是A需要在创建B之前初始化)
- 析构函数:
- B不继承A的dtor李>
- 退出后,B的析构函数将自动调用A的析构函数
原创帖子 当您在Google上搜索“C++析构函数继承站点:stackoverflow.com”时,您当前会发现以下帖子:
尽管从帖子中可以很清楚地看出析构函数似乎是继承的,但我仍然感到困惑的是,一个拥有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();
}
Q2:任何认为这不是遗传的人能解释一下吗
Q3:那么,当您使用输入调用子类的构造函数时会发生什么?超类的“空构造函数”也被调用了吗
Q1:我从实践中也知道,如果不为派生类显式定义构造函数,就无法使用与其父构造函数相同的原型初始化派生对象,对吗
除了在超类中定义默认构造函数的简单情况外,是的,您是正确的
Q2:任何认为这不是遗传的人能解释一下吗 这可能是术语定义的问题。虽然很明显,虚拟析构函数存在并工作“如预期”,但我们在C++标准([Copy.Virtu])中看到: 即使析构函数不是继承的,派生类中的析构函数也会重写声明为虚拟的基类析构函数 (强调矿山)
Q3:那么,当您使用输入调用子类的构造函数时会发生什么?超类的“空构造函数”也被调用了吗
如果没有显式调用特定的超类构造函数,则将调用默认的超类构造函数(假设它是可见的)。术语、术语 好的,我们所说的“Foo是继承的”是什么意思?我们的意思是,如果类
A
的对象在其接口中有Foo
,那么类B
的对象(它是A
的子类)在其接口中也有Foo
- 构造函数不是对象接口的一部分。他们直接属于阶级。类
和A
可以提供完全不同的构造函数集。这里没有“被继承” (实现细节:每个B的构造函数调用一些A的构造函数。)B
- 析构函数确实是每个对象界面的一部分,因为对象的用户负责调用它们(即直接使用
或间接地让对象超出范围)每个对象只有一个析构函数:它自己的析构函数,也可以是虚拟析构函数。它总是自己的,不是继承的 (实现细节:B的析构函数调用A的析构函数。)delete
我希望这能回答您的想法。析构函数不是继承的。如果一个类没有定义一个类,编译器将生成一个类。对于普通情况,析构函数只调用基类的析构函数,这通常意味着它的析构函数(模仿继承)没有显式代码。但是,如果一个类的成员带有析构函数,则生成的析构函数会在调用基类的析构函数之前调用这些成员的析构函数。这是继承函数无法做到的。继承就是这样一种机制:重用和扩展现有类而不修改它们,从而在它们之间产生层次关系 继承类似于将对象嵌入到类中 当类继承一个基类时,基类的构造函数首先被调用,,然后是派生类,析构函数的调用是相反的顺序 那么为什么调用基类构造函数(调用not Inheritable可能带有参数/默认值):以确保在执行派生类的构造函数时正确构造基类 现在调用析构函数(调用not inherit):当基本对象超出范围时,析构函数将自己调用。因此dest的继承存在np问题
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)
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
}
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.
I would want to express my thoughts. Creating any object is done in two stages: