假期 2020.02.02
学习总结资源来源于中国大学MOOC,c语言中文网
定义
类的构造函数是类的一种特殊的成员函数,它会在每次创建类的新对象时执行。
系统默认构造函数:默认的构造函数没有任何参数
class Complex { private :
double real, imag;
public:
void Set( double r, double i);
}; //编译器自动生成默认构造函数
Complex c1; //默认构造函数被调用
Complex * pc = new Complex; //默认构造函数被调用
构造函数的名称与类的名称是完全相同的,并且不会返回任何类型,也不会返回 void。如果需要,构造函数也可以带有参数且构造函数可用于为某些成员变量设置初始值。
#include<iostream>
using namespace std;
class complex {
private:
double real, imag;
public:
void set() {
cout << real <<" "<< imag << endl;
}
complex(double r, double i = 2);//有参
complex(complex r, complex i);
};
//成员函数定义
complex::complex(double a, double b)
{
real = a;
imag = b;
}
complex::complex(complex r, complex i)
{
real = r.real + i.real;
imag = r.imag + i.imag;
}
int main()
{
complex c(2);
c.set();
complex c1(3,1);
c1.set();
complex c2(2, 3);
c2.set();
complex c3(c1, c2);
c3.set();
return 0;
}
执行效果
注意:
C++ 初始化类成员时,是按照声明的顺序初始化的,而不是按照出现在初始化列表中的顺序。
class abc {
private:
int m_x;
int m_y;
public:
abc(int x, int y);
void show();
};
void abc::show()
{
cout << m_x << " " << m_y << endl;
}
abc::abc(int x, int y):m_y(y), m_x(m_y){};
int main()
{
abc c(3, 4);
c.show();
return 0;
}
你可能以为上面的代码将会首先做 m_y=I,然后做 m_x=m_y,最后它们有相同的值。但是编译器先初始化 m_x,然后是 m_y,,因为它们是按这样的顺序声明的。结果是 m_x 将有一个不可预测的值。
执行效果
构造函数注意事项
- 可以有多个构造函数,参数个数或类型不同
class complex {
private:
double real, imag;
public:
void set() {
cout << real <<" "<< imag << endl;
}
complex(double r, double i = 2);//有参
complex(complex r, complex i);
};
//成员函数定义
complex::complex(double a, double b)
{
real = a;
imag = b;
}
complex::complex(complex r, complex i)
{
real = r.real + i.real;
imag = r.imag + i.imag;
}
- 构造函数最好是public的,private构造函数 不能直接用来初始化对象
构造函数在数组中的使用
class csample {
int x;
public:
csample() {
cout << "1" << endl;
}
csample(int n) {
x = n;
cout << "2" << endl;
}
};
int main()
{
csample arry1[2];
cout << "step1" << endl;
csample arry2[2] = { 1,2 };
cout << "step2" << endl;
csample arry3[2] = { 3 };
cout << "step3" << endl;
csample* arry4 = new csample[2];
delete[]arry4;
return 0;
}
csample arry1[2];
默认无参数初始化csample arry2[2] = { 1,2 };
两个参数初始化两个类csample arry3[2] = { 3 };
初始化为一个有参数一个无参数初始化csample* arry4 = new csample[2];
初始化为指针的类,带地址
class test {
public:
test(int n){ }
test(int n,int m){ }
test(){ }
};
int main()
{
test arry1[3] = { 1,test(1,2), };
test arry2[3] = { test(2,3),test(1,2),1 };
test* arry3[3] = { new test(4),new test(1,2) };
return 0;
数组类的不同的初始化方式(以上为)
其中test* arry3[3] = { new test(4),new test(1,2) };
只生成了两个类对象,第三个为空指针,无意义,即使加入NULL
也一样。如A * arr[4] = { new A(), NULL,new A() };
构造函数的复制
只有一个参数,即对同类的象的引用,如
complex::complex(complex &)
或
complex::complex(const complex &)
两者选一,但加上 const 是更好的做法,这样复制构造函数才能接受常量对象作为参数,即才能以常量对象作为参数去初始化别的对象。但在实际运用中不仅仅可以实现复制功能,还可以实现其他功能。
- 如果没有定义复制构造函数,那么编译器会默认生成复制构造函数
class Complex {
private :
double real,imag;
};
//调用缺省无参构造函数
Complex c1;
//调用缺省的复制构造函数,将 c2 初始化成和c1一样
Complex c2(c1);
可执行代码
#include<iostream >
using namespace std;
class complex
{
public:
double real, imag;
complex(double r, double i) {
real = r; imag = i;
}
void show(){
cout << real << " " << imag << endl; //输出
}
};
int main() {
complex cl(1, 2);
complex c2(cl); //用复制构造函数初始化c2
c2.show();
return 0;
}
执行结果
2. 如果定义的自己的复制构造函数, 则将编译器不会构造默认的复制构造函数
#include<iostream>
using namespace std;
class complex {
private:
int real, imag;
public:
complex(){}//默认构造函数,不写会出现错误,因为默认构造函数只出现在无构造函数类中
complex(const complex& c);//构造复制函数
};
complex::complex(const complex& c) {
real = c.real;
imag = c.imag;
cout << "be Called" << endl;
}
int main()
{
complex c1;//默认构造函数初始化
complex c2(c1);//调用自己定义的复制构造函数
return 0;
}
执行效果
3. 不允许有形如 complex::complex( complex)的构造函数。
复制构造函数常用于:
- 当用一个对象去初始化同类的另一个对象时,以下两句都会出现复制构造函数:
Complex c2(c1);
Complex c2 = c1; //初始化语句,非赋值语句
- 如果某函数有一个参数是类A 的对象, 那么该函数被调用时,类A的复制构造函数将被调用。换句话说,作为形参的对象,是用复制构造函数初始化的,而且调用复制构造函数时的参数,就是调用函数时所给的实参,注意如果形参是一个对象,那么形参的值是否等于实参,取决于该对象所属的类的复制构造函数是如何实现的。
class A {
public:
A() { };
A( A & a){
cout << "Copy constructor called" <<endl;
}
};
void Func(A a1){ } ;
int main()
{
A a2;
Func(a2); //形参 a2 在初始化时调用了复制构造函数
return 0;
}
- 如果函数的返回值是类A的对象时,则函数返回时, A的复制构造函数被调用,因为作为函数返回值的对象是用复制构造函数初始化的,而调用复制构造函数时的实参,就是 return 语句所返回的对象:
A Func()
{
A b(4); return b;
}
int main()
{
cout << Func().v << endl;
return 0;
}
注:1. 默认构造函数(即无参构造函数)不一定存在,但是复制构造函数总是会存在。
以对象作为函数的形参,在函数被调用时,生成的形参要用复制构造函数初始化,这会带来时间上的开销。如果用对象的引用而不是对象作为形参,就没有这个问题了。但是以引用作为形参有一定的风险,因为这种情况下如果形参的值发生改变,实参的值也会跟着改变。解决办法就是将形参声明为对象的 const 引用。
2. 对象间赋值并不导致复制构造函数被调用。