今天使用派生类时又发现了一个问题,基类和派生类的代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13class Base
{
public:
Base(int a)
{ }
};
class Derived : public Base
{
public:
Derived()
{ }
};
还没编译,Creator就已经报错了
编译时Derived类会报错: error: no matching function for call to ‘Base::Base()’
这个问题的实质还是默认构造函数。我们都知道,如果一个类没有构造函数,编译器会为我们自动创建一个默认构造函数,这个函数没有参数,什么都没做。但是,当我们实现一个构造函数之后,编译器就不会创建,因此Base没有默认构造函数。
默认构造函数就是在调用时不需要explicitly传入实参的构造函数 |
上面我定义的Base(int a)
是构造函数,而不是默认构造函数。 C++中,最多有一个默认构造函数,刻意是编译器生成,也可以是我们自己定义的。我们自己定义的默认构造函数只能是两种:
- 无参 2. 有参数,但参数都有默认值
比如下面两种都是默认构造函数:1
2
3
4
5
6
7
8
9
10
11
12
13class Base
{
public:
Base()
{ }
};
// 或者有默认值的有参构造函数
class Base
{
public:
Base(int a=0)
{ }
};
但是不要把这两种构造函数都放入类里,因为最多只能有一个默认构造函数。不实例化不报错,一旦实例化就会报错: 指定了多个默认构造函数,对重载函数调用不明确
派生类构造函数对基类初始化
再回到上面的问题1
2
3
4
5
6
7
8
9
10
11
12
13class Base{
public:
Base(int value){}
};
class Derived : public Base
{
public:
Derived()
{ }
private:
int m_value;
};
现在加入派生类,以上的代码会报错: error: constructor for ‘Derived’ must explicitly initialize the base class ‘Base’ which does not have a default constructor
如果基类没有默认构造函数,那么编译器也不会为派生类隐式地定义默认构造函数, 就会出现上面的错误。对这种错误,有两种修改方法:
对于有参的构造函数,参数赋默认值。也就是改成默认构造函数:把
Base(int a)
改为Base(int a=0)
最常用,也是Qt中所用的:在派生类的构造函数后,用列表初始化的方式调用基类构造函数
1
2
3
4
5
6
7
8
9class Derived : public Base
{
public:
Derived():
Base(m_value)
{ }
private:
int m_value;
};
上面的问题,可以总结如下:
- 基类没有显式声明构造函数或者有一个无参数的构造函数,派生类构造函数可以不用对基类初始化,即忽略基类的构造函数
- 基类的构造函数全是有参数的,派生类必须至少实现一个基类的构造函数,例如Qt中常见的:
1 | explicit MainWindow(QWidget* parent=0); |
这种方式解决的问题是:使用派生类创建一个对象后,怎样初始化从基类中继承过来的数据成员?(基类的构造函数是不能被继承的)
这种代码的具体格式:1
2
3
4派生类::派生类构造函数(总参数列表):基类构造函数(参数列表)
{
派生类中的数据成员初始化;
}
注意:如果没有基类和派生的关系,就不能用这种初始化格式,否则报错。
C++11中的default关键字
之前说了,如果我们显式声明构造函数,编译器就不会生成默认构造函数。 但是有时候,我们反而需要一个默认构造函数,比如下面的情况:1
2
3
4
5
6
7
8
9
10
11
12class C
{
public:
C(int f)
{
qDebug()<<"construct" ;
}
int a;
long b;
};
C obj;
很显然会报错,因为不存在默认构造函数了。我们可以加一个构造函数:C()=default;
,这样编译就通过了
但是以下用法都会报错:1
2Base(double value=0)=default;
Base(float value)=default;
這是因为= default
只能被加在 沒有默认参数 的special member function
后面,Special member function
包含: Default constructor, Destructor, Copy constructor, Copy assignment, Move constructor, Move assignment