C++的构造函数和默认构造函数详解
构造函数是c++面向对象中的一个重难点,于是我查找了各大网站将资料汇总一下,供自己和其他朋友们参考。
首先我们来看看构造函数的分类:
class Complex
{
private :
double m_real;
double m_imag;
public:
// 无参构造函数
// 如果创建一个类你没有写任何构造函数,则系统会自动生成默认的无参构造函数,函数为空
// 只要你写了一个下面的某一种构造函数,系统就不会再自动生成这样一个
//默认构造函数,如果希望有一个这样的无参构造函数,则需要自己显式地写出来
Complex(void)
{
m_real = 0.0;
m_imag = 0.0;
}
// 一般构造函数
// 一般构造函数可以有各种参数形式,一个类可以有多个一般构造函数,前提
//是参数的个数或者类型不同(基于c++的重载函数原理)
// 例如:你还可以写一个 Complex( int num)的构造函数出来
// 创建对象时根据传入的参数不同调用不同的构造函数
Complex(double real, double imag)
{
m_real = real;
m_imag = imag;
}
// 复制构造函数(拷贝构造函数)
// 复制构造函数参数为类对象本身的引用,用于根据一个已存在的对象
//复制出一个新的该类的对象,一般在函数中会将已存在对象的数据成员的值复制一份到新创建的对象中
// 若没有显示的写复制构造函数,则系统会默认创建一个复制构造函数,但当类中
//有指针成员时,由系统默认创建该复制构造函数会存在风险
Complex(const Complex & c)
{
// 将对象c中的数据成员值复制过来
m_real = c.m_real;
m_img = c.m_img;
}
// 类型转换构造函数,根据一个指定的类型的对象创建一个本类的对象
// 例如:下面将根据一个double类型的对象创建了一个Complex对象
Complex::Complex(double r)
{
m_real = r;
m_imag = 0.0;
}
// 等号运算符重载
// 注意,这个类似复制构造函数,将=右边的本类对象的值复制给等号
//左边的对象,它不属于构造函数,等号左右两边的对象必须已经被创建
// 若没有显示的写=运算符重载,则系统也会创建一个默认的=运算符重载,只做一些基本的拷贝工作
Complex &operator=(const Complex &rhs)
{
// 首先检测等号右边的是否就是左边的对象本,若是本对象本身,则直接返回
if ( this == &rhs )
{
return *this;
}
// 复制等号右边的成员到左边的对象中
this->m_real = rhs.m_real;
this->m_imag = rhs.m_imag;
// 把等号左边的对象再次传出
// 目的是为了支持连等 eg: a=b=c 系统首先运行 b=c
// 然后运行 a= ( b=c的返回值,这里应该是复制c值后的b对象)
return *this;
}
};
void main()
{
// 调用了无参构造函数,数据成员初值被赋为0.0
Complex c1,c2;
// 调用一般构造函数,数据成员初值被赋为指定值
Complex c3(1.0,2.5);
// 也可以使用下面的形式
Complex c3 = Complex(1.0,2.5);
// 把c3的数据成员的值赋值给c1
// 由于c1已经事先被创建,故此处不会调用任何构造函数
// 只会调用 = 号运算符重载函数
c1 = c3;
// 调用类型转换构造函数
// 系统首先调用类型转换构造函数,将5.2创建为一个本类的
//临时对象,然后调用等号运算符重载,将该临时对象赋值给c1
c2 = 5.2;
// 调用拷贝构造函数( 有下面两种调用方式)
Complex c5(c2);
Complex c4 = c2; // 注意和 = 运算符重载区分,这里等号左边的对象不
//是事先已经创建的,故需要调用拷贝构造函数,参数为c2
}
下面再从定义出发,看看构造函数和默认构造函数的区别:
构造函数是c++的类在构造对象时调用的函数,此函数没有返回类型。
默认构造函数是未提供显式初始值时用来构建对象的构造函数。
其实这个定义并没有告诉我们什么详细的细节,真正想要搞懂还是要看看代码,从代码的区别来体会他们两个之间的差异。
class A
{
private:
int _a;
int _b;
public:
A(); // 默认构造函数
A(int a, int b); // 构造函数
A(int a = 10, int b = 2); // 默认构造函数
};
其实如果我们没有提供任何构造函数,系统会自己帮我们加上一个默认构造函数,就像A() {};一样。当然,如你所见这个函数是空的,他不能做任何事,但是他却并不是一无是处,他的作用就是保证程序能够正确运行。
如果我们要自己定义一个默认构造函数,那我们有两种方法:
1.定义一个无参的构造函数(例如上面的A(); )
2.定义所有参数都有默认值的构造函数 (例如上面的 A(int a = 10, int b = 2); )
重点来了!切记一个类只能有一个默认构造函数!也就是说上面提到的两个方法你只能选其中的一种,不过我们大多数情况下还是选择第一种。
另外,如果我们已经定义了构造函数,则系统不会再给我们加上默认构造函数了,这也就要求我们最好自己将默认构造函数写上,防止出现未初始化的错误。
2019年4月7日