我遇到了这个询问其输出的问题。
#include<iostream>
using namespace std;
class A{
public:
int i;
A(int j=3):i(j){}
};
class B:virtual public A{
public:
B(int j=2):A(j){}
};
class C:virtual public A{
public:
C(int j=1):A(j){}
};
class D:public B, public C {
public:
D(int j=0):A(j), B(j+1), C(j+2){}
};
int main()
{
D d;
cout<<d.i;
return 0;
}
有些事情我不明白。 请澄清这些疑惑。我不能谷歌,因为我不知道该搜索什么。
Q1。在代码中使用参数化构造函数。只需冒号(:)后我们编写父类的构造函数。如何
A(int j=3):i(j){}
用了吗?因为我不是一个班级。
Q2。在类D中,类的构造函数使用构造函数来初始化基类。但是可以看出,所有构造函数仅修改类A的变量i。 那么在这里调用的构造函数的序列是什么。
我知道当我们不调用父类的构造函数时,它被显式调用并且顺序是众所周知的,但是当我们像这里隐式调用构造函数时那样。
Q3。尽管参数被初始化,我们在构造函数中发送的值似乎也有所不同。为什么会这样?
答案 0 :(得分:4)
A1。 :i(j)
中的A(int j=3):i(j){}
是初始化列表。初始化列表可以指定如何初始化父类和成员变量。 (j)
是i
的初始化程序,其行为类似于本地变量的初始化:int i(j);
。 (您可能更熟悉初始化语法int i = j;
,它类似。您不能在初始化列表中使用=
语法。)
A2。虚拟基类始终由最派生类的构造函数初始化。因此D
的构造函数初始化其A
基类,当D
的构造函数调用B
和C
的构造函数时,这些构造函数不会重新初始化A
。
A3。语法D(int j=0)
不初始化参数。相反,它为参数声明默认值,只要您明确传递该参数的值,就会忽略该参数。
答案 1 :(得分:3)
ctor-initializer-list 包含所有子对象的初始值设定项。这意味着基类子对象和成员子对象。
子对象始终按照它们在类定义中出现的顺序进行初始化。将它们放在 ctor-initializer-list 中的顺序无关紧要(尽管在忽略订单时将它们置于任何其他顺序会令人困惑)。
继承的基础子对象构造函数由直接派生的类的构造函数调用...除了虚拟基础子对象之外,虚拟基础子对象直接从构造函数中为最派生对象调用。虚拟基础子对象先于其他任何东西构建。
没有“参数被初始化”这样的东西。这些是默认参数,并且在提供实际参数时会被忽略。
答案 2 :(得分:0)
1)冒号:
可以在构造函数中用于调用具有给定参数的成员变量的构造函数:
public:
int i;
A(int j=3):i(j){}
表示A
的成员i
将使用j
作为参数调用其构造函数。
2)子对象将按照它们出现在类定义
中的顺序进行初始化class D:public B, public C
3)他们没有被初始化,他们被给予默认参数。
答案 3 :(得分:0)
Q1: 函数签名之间和函数体开头括号之间的构造函数中的代码称为初始化列表。
初始化列表的语法是具有相应初始值的类的成员变量的列表。初始值在括号中。成员变量由逗号分隔。第一个变量在冒号之后。
初始化列表还可以包含基类的构造函数,这是您的B和C类所做的。您的'A'类只使用初始化成员变量的表单。
Q2: 要查找执行构造函数的顺序,请输入一些print语句。它将帮助您了解施工顺序。也放入析构函数并将print语句也放入其中。在这个问题上,我无法为你完成所有的功课。 :)
Q3: 我想通过参数初始化你的意思是默认参数?如果值实际传递给函数,则始终会覆盖默认参数。