继承到派生类的基构造函数
Base constructors inherited to derived class?
我一直认为基类构造函数/析构函数/友元不是由派生类继承的。此链接证实了这一点:http://www.geeksforgeeks.org/g-fact-4/.
我还知道,我们可以在派生类初始化器列表的初始化列表中编写基类构造函数。
话虽如此:我今天试着检查一下我的技能。但我没能猜到这个程序的输出。
#include<iostream>
class A {
int x, y;
public:
A(int a = 0, int b = 0) : x(a), y(b) {
std::cout << "A ctor called" << std::endl;
}
void print_A() {
std::cout << "x = " << x << std::endl;
std::cout << "y = " << y << std::endl;
}
};
class B : public A {
int z;
public:
// I knew that A member can be initilized like this.
B(int a = 0, int b = 0, int c = 0) : z(a), A(b, c) {
std::cout << "C ctor called" << std::endl;
// I was not aware about that.
A(b, c);
}
void print_B() {
std::cout << "z = " << z << std::endl;
}
};
int main() {
B b(1, 2, 3);
b.print_A();
b.print_B();
}
输出:
A ctor called
C ctor called
A ctor called
x = 2
y = 3
z = 1
几个问题:
如果构造函数/解构造函数/友元不是从基继承的,那么类"B"如何能够访问类"A"的构造函数。
你是怎么得到这个输出的?为什么已经调用了"A"的两个构造函数。
您的理解有误。此:
// I was not aware about that.
A(b, c);
没有初始化B的A成员,它(至少在名义上)在构造函数的主体中创建了一个临时的、无名称的局部变量,有点类似于你说的:
A a(b, c);
A的构造函数是一个公共成员,所以任何东西都可以调用它
如果构造函数/解构造函数/友元不是从基继承的,那么类"B"如何能够访问类"A"的构造函数?
"未继承"并不意味着"派生类无法访问"。派生类当然可以引用基构造函数。B
的构造函数做了两次:
- 第一次访问在初始化列表中
- 第二个访问位于
B
的构造函数的主体中;它创建了一个临时对象
继承构造函数意味着B
的用户将能够访问B(int, int)
,而他们不能这样做*。
它看起来像是一个构造函数调用。为什么它要创建一个临时对象?
考虑这个方法:
void foo(const A& a);
一种常见的方法是这样称呼它:
A a(1, 2);
foo(a);
但C++也允许您调用它,而无需在单独的行上创建A
:
foo(A(1, 2));
在这种情况下,C++创建一个临时对象,并将引用传递给foo
A(1, 2)
C++还通过调用其构造函数为您创建一个临时对象。
为什么已经调用了"A"的两个构造函数。
构造函数被调用两次;这就是你得到输出的原因。
*C++11的using
机制允许您实现与构造函数继承非常相似的效果,前提是您遵循特定的规则。
每次调用A(b,c)时都会调用构造函数;
你在上打电话
B(int a = 0, int b = 0, int c = 0) : z(a), A(b, c) {
你在b构造函数中调用它
// I was not aware about that.
A(b, c);
代码按预期工作
如果构造函数/解构造函数/友元不是从基继承的,那么类"B"如何能够访问类"A"的构造函数。
你是说在这几行?
// I was not aware about that.
A(b, c);
它并不是你认为的"访问构造函数"。它只是在构造函数的主体中创建(并立即丢弃)一个匿名的临时A
。
您是如何获得此输出的?为什么已经调用了"A"的两个构造函数。
因为您创建了A
的两个实例:B b
的基类子对象和匿名临时对象。
这里有一个简单的实验来验证这一点,使用以下日志:
// in A
A(int a = 0, int b = 0) : x(a), y(b) {
std::cout << "A::A @" << static_cast<void*>(this) << std::endl;
}
~A() {
std::cout << "A::~A @" << static_cast<void*>(this) << std::endl;
}
// in B
B(int a = 0, int b = 0, int c = 0) : z(a), A(b, c) {
std::cout << "B::B @" << static_cast<void*>(this) << std::endl;
A(b, c);
}
~B() {
std::cout << "B::~B @" << static_cast<void*>(this) << std::endl;
}
我得到类似的输出
A::A @0xffec7054
B::B @0xffec7054
A::A @0xffec704c
A::~A @0xffec704c
x = 2
y = 3
z = 1
B::~B @0xffec7054
A::~A @0xffec7054
请注意,第二个A::A
的实例地址与第一个不同(因此它是一个不同的对象),后面跟着一个A::~A
(因为匿名临时会立即超出范围)。
备注:
如果你可以像最初建议的那样"调用构造函数",它看起来就像
auto subobject = static_cast<A*>(this); new (subobject) A(b, c);
这将是非常错误的。
b
的A
子对象是在B
的构造函数主体开始之前,当它自己的构造函数完成时完全构造的。你不能在同一个空间里重新创建一个新对象,旧对象会发生什么?这可能看起来微不足道,但对于具有动态分配资源的对象来说,这将是一个严重的错误。这是不允许的。
您编写了初始化器列表
: z(a), A(b, c)
,但应该注意,基类子对象将在初始化派生类成员之前构造。也就是说,这两件事将以与你所写相反的顺序发生。这不一定是一个错误,但值得知道。
- 如何委托派生类使用其父构造函数?
- 如果基类包含双指针成员,则派生类的构造函数
- C++:为什么无法在派生类中访问受保护的构造函数?
- C++派生的类构造函数
- 添加自定义析构函数时,Move 构造函数在派生类中消失
- 在没有默认构造函数的情况下创建的派生对象
- 派生类(构造函数具有参数)和基类(构造函数缺少参数)之间没有可行的转换
- 如何在派生构造函数中多次构造基类
- C++(控制台)构造函数和派生类
- 为什么为派生类定义复制构造函数需要定义基类的默认构造函数?
- 在dynamic_pointer_cast后调用派生类的构造函数
- 如何使用函数(而不是构造函数)将派生类对象分配给基类指针
- 将派生类的构造函数声明为父类的友元
- 如何为具有私有成员的派生类实现移动构造函数
- 使用回调函数从构造函数调用虚拟/派生方法的替代方法?
- 在派生自线程类的构造函数中传递字符串
- C++ 为什么要将对基类的引用传递给派生类的构造函数
- C++将派生类的const值传递给基意外行为的构造函数
- 在模板派生类中继承具有类型别名的构造函数
- 正在调用基方法,而不是从构造函数派生方法