在stackoverflow上找到了一篇文章,写的蛮好的,地址如下:
https://stackoverflow.com/questions/276173/what-are-your-favorite-c-coding-style-idioms#comment60171463_2034439
由于是英文的,且比较重要,于是总结成下面几条!
今天开始学习第一节类初始化列表,代码也是会放在《C++那些事》中,链接如下:
https://github.com/Light-City/CPlusPlusThings
第一种:使用初始化列表。
class Animal {
public:
Animal() {
std::cout << "Animal() is called" << std::endl;
}
Animal(const Animal &) {
std::cout << "Animal (const Animal &) is called" << std::endl;
}
Animal &operator=(const Animal &) {
std::cout << "Animal & operator=(const Animal &) is called" << std::endl;
return *this;
}
~Animal() {
std::cout << "~Animal() is called" << std::endl;
}
};
class Dog {
public:
Dog(const Animal &animal) : __animal(animal) {
std::cout << "Dog(const Animal &animal) is called" << std::endl;
}
~Dog() {
std::cout << "~Dog() is called" << std::endl;
}
private:
Animal __animal;
};
int main() {
Animal animal;
std::cout << std::endl;
Dog d(animal);
std::cout << std::endl;
return 0;
}
运行结果:
Animal() is called
Animal (const Animal &) is called
Dog(const Animal &animal) is called
~Dog() is called
~Animal() is called
~Animal() is called
依次分析从上到下:
main函数中Animal animal;
调用默认构造。
Dog d(animal);
等价于:
Animal __animal = animal;
实际上就是调用了拷贝构造,因此输出了:
Animal (const Animal &) is called
再然后打印Dog的构造函数里面的输出。
最后调用析构,程序结束。
第二种:构造函数赋值来初始化对象。
构造函数修改如下:
Dog(const Animal &animal) {
__animal = animal;
std::cout << "Dog(const Animal &animal) is called" << std::endl;
}
此时输出结果:
Animal() is called
Animal() is called
Animal & operator=(const Animal &) is called
Dog(const Animal &animal) is called
~Dog() is called
~Animal() is called
~Animal() is called
于是得出:
当调用Dog d(animal);
时,等价于:
先定义对象,再进行赋值,因此先调用了默认构造,再调用=操作符重载函数。
// 假设之前已经有了animal对象
Animal __animal;
__animal = animal;
小结
通过上述我们得出如下结论:
现考虑把上述的关系改为继承,并修改Animal与Dog的构造函数,如下代码:
class Animal {
public:
Animal(int age) {
std::cout << "Animal(int age) is called" << std::endl;
}
Animal(const Animal & animal) {
std::cout << "Animal (const Animal &) is called" << std::endl;
}
Animal &operator=(const Animal & amimal) {
std::cout << "Animal & operator=(const Animal &) is called" << std::endl;
return *this;
}
~Animal() {
std::cout << "~Animal() is called" << std::endl;
}
};
class Dog : Animal {
public:
Dog(int age) : Animal(age) {
std::cout << "Dog(int age) is called" << std::endl;
}
~Dog() {
std::cout << "~Dog() is called" << std::endl;
}
};
上述是通过初始化列表给基类带参构造传递参数,如果不通过初始化列表传递,会发生什么影响?
去掉初始化列表
Dog(int age) {
std::cout << "Dog(int age) is called" << std::endl;
}
运行程序:
error: no matching function for call to ‘Animal::Animal()’
由于在Animal中没有默认构造函数,所以报错,遇到这种问题属于灾难性的,我们应该尽量避免,可以通过初始化列表给基类的构造初始化。
特别是引用数据成员,必须用初始化列表初始化,而不能通过赋值初始化!
例如:在上述的Animal中添加私有成员,并修改构造函数:
class Animal {
public:
Animal(int age,std::string name) {
std::cout << "Animal(int age) is called" << std::endl;
}
private:
int &age_;
const std::string name_;
};
报下面错误:
error: uninitialized reference member in ‘int&’
应该改为下面:
Animal(int age, std::string name) : age_(age), name_(name) {
std::cout << "Animal(int age) is called" << std::endl;
}