C++语法系列之10--构造函数总结
2018-04-15 本文已影响0人
hello12qwerz
1 不提供显示的构造函数
class Counter {
private:
int cnt;
public getCnt() {
return cnt;
}
}
Counter myCnt;//在堆栈中,此时会自动调用默认构造函数初始化myCnt
myCnt.getCnt();//0
此时编译器会默认为类生成一个默认构造函数(不带参数的构造函数,什么也不做)。上例中打印结果为0(类中定义的成员变量,基本类型会初始化为0)。
编译器提供的默认构造函数相当于:
Counter() {
//空实现
}
2 显示的提供构造函数
class Counter {
private:
int mA;
float mB;
public:
Counter(int a);
Counter(int a, float b);
};
Counter::Counter(int a) {
mA = a;
}
Counter::Counter(int a, float b) {
mA = a;
mB = b;
}
int main(int argc, const char * argv[]) {
//Counter cnt;//error, cannot compile
Counter myCnt(1);
Counter myCnt2(1,3.0);
}
上面的例子提供了2个构造函数(也即重载构造函数)。
3 复制构造函数
复制构造函数的参数为对象的引用
class Counter {
private:
int mA;
float mB;
public:
Counter(int a);
Counter(int a, float b);
Counter(const Counter& c);
int getMA() const;
};
Counter::Counter(int a) {
mA = a;
}
Counter::Counter(int a, float b) {
mA = a;
mB = b;
}
Counter::Counter(const Counter& c) {
mA = c.mA;
mB = c.mB;
}
int Counter::getMA() const {
return mA;
}
int main(int argc, const char * argv[]) {
Counter myCnt(1,3.0);
Counter myCopyCnt(myCnt);
cout << myCopyCnt.getMA() << endl;
}
注意:
- 复制构造函数只在初始化的时候才会调用。如果是赋值而不是初始化,那么调用的是赋值运算符,而不是复制构造函数。
- 浅拷贝/深拷贝:复制构造函数和赋值运算符,如果有指针数据成员,涉及到内存分类的场景的话,需要考虑浅拷贝/深拷贝。浅拷贝只是将引用或者指针指向对应的成员变量。而深拷贝则会分配内存,然后将引用指向对应的内存。
4 类型转换构造函数
class Complex {
private:
float mReal;
float mImg;
public:
Complex();
Complex(float real);
Complex(const Complex& c);
Complex operator+(const Complex& c);
float getReal() const;
float getImg() const;
void setReal(float real);
void setImg(float img);
};
Complex::Complex() {
mReal = 0.0;
mImg = 0.0;
}
Complex::Complex(const Complex& c) {
mReal = c.mReal;
mImg = c.mImg;
}
Complex::Complex(float real) {
mReal = real;
mImg = 0;
}
float Complex::getReal() const {
return mReal;
}
float Complex::getImg() const {
return mImg;
}
Complex Complex::operator+(const Complex& c) {
Complex complex;
complex.setReal(mReal + c.getReal());
complex.setImg(mImg + c.getImg());
return complex;
}
int main(int argc, const char * argv[]) {
Complex complex;
Complex c1 = 1.0f;
cout << "real:" << c1.getReal() << ";img:" << c1.getImg() << endl;
# real: 1.0; img:0.0
Complex a(2.0);
Complex b = a + 1.0;//real: 3.0
}
- 上面的例子中,Complex c1= 1.0f; 会调用Complex的构造函数Complex(float real),也就是类型转换.
- Complex b = a + 1.0 此时提供了operator+,也会隐式的调用构造函数进行类型转换。但是Complex c = 1.0 + a;无法编译通过,因为Complex的operator+运算符不具有交换性,如果要可以编译通过,必须提供全局的operator+ 才可以。
5 禁止隐式调用构造函数进行类型转换
有些时候,上面的效果是我们期望的。但是有些时候,如果不是我们需要的(比如错误的写了Complex c1 = 1.0f),如何禁止这种类型转换呢?
可以使用explicit关键字解决:
class Complex {
private:
float mReal;
float mImg;
public:
Complex();
explicit Complex(float a);
Complex(const Complex& c);
Complex operator+(const Complex& c);
float getReal() const;
float getImg() const;
void setReal(float real);
void setImg(float img);
};
Complex::Complex() {
mReal = 0.0;
mImg = 0.0;
}
Complex::Complex(const Complex& c) {
mReal = c.mReal;
mImg = c.mImg;
}
Complex::Complex(float a) {
mReal = a;
mImg = 0;
}
float Complex::getReal() const {
return mReal;
}
float Complex::getImg() const {
return mImg;
}
void Complex::setImg(float img) {
mImg = img;
}
void Complex::setReal(float real) {
mReal = real;
}
int main(int argc, const char * argv[]) {
Complex complex;
Complex c1 = 1.0f; //error,此时无法将float类型转换为Complex
Complex c2(1.0f); //此时必须这样显示的调用构造函数
注意:
1)explicit用于用于只有一个参数的构造函数才有效;
2)假如构造函数有两个参数,explicit无效;
3)假如构造函数有2个或者多个参数,但是除了第一个参数外,其余均带有默认值时,explicit有效;
6 赋值运算符
//为了支持连等操作(形如这样: a =b =c ),返回值必须为引用
Complex &operator=(const Complex &rhs)
{
if ( this == &rhs )
{
return *this;
}
// 复制等号右边的成员到左边的对象中
this->mReal = rhs.mReal;
this->mImg = rhs.mImg;
return *this;
}
以上是一个赋值运算符的例子,没有涉及到内存分配。所以看不出来深拷贝和浅拷贝的区别。如果有引用和指针,涉及到内存分配,那么需要使用深拷贝。
7 带有默认值的构造函数
class Base {
public:
Base();
Base(int a = 0);
private:
int mA;
};
Base::Base() {
}
Base::Base(int a) {
mA = a;
}
int main(int argc, const char * argv[]) {
Base b;//Error: Call to constructor of "Base" is ambiguous
return 0;
}
以上代码定义了两个构造函数:无参构造函数和带有默认值得构造函数。由于无法这两个构造函数,编译会出错。
所以:定义构造函数时,不允许定义导致歧义的构造函数。
8 继承层次的构造函数默认值
class Base {
public:
Base(int a = 0);
virtual ~Base();
private:
int mA;
};
Base::Base(int a) {
mA = a;
cout << "Base a = " << mA << endl;
}
Base::~Base() {
}
class Derived : public Base {
public:
Derived(int a = 1);
virtual ~Derived();
};
Derived::Derived(int a) {
cout <<"Derived a = " << a << endl;
}
Derived::~Derived() {
}
int main(int argc, const char * argv[]) {
Derived d;
cout << endl << endl;
Base* b = new Derived();
return 0;
}
运行结果如下:
Base a = 0
Derived a = 1
Base a = 0
Derived a = 1
说明:C++中默认参数不会继承。C++根据描述对象的表达式类型绑定默认参数,而不是根据实际的对象类型绑定参数。