CPP:构造函数&成员初始化表&拷贝构造函数

构造函数

类对象构造顺序

类对象的构造顺序是这样的:

1.分配内存,调用构造函数时,隐式/显示的初始化各数据成员(构造函数列表的初始化方式不是按照列表的的顺序,而是按照变量声明的顺序同时初始化显隐数据成员);

2.进入构造函数后在构造函数中执行一般赋值与计算。

例子1

class A {
public:
	int x;
	const int y;
	int& z;
	A() :y(1), z(x), x(0) { x = 100; }
};

void main() {
	A a;
	cout << "a.x:" << a.x << "   a.y:" << a.y << "   a.z:" << a.z << endl;
}

执行顺序为:

  1. 初始化x(0) 初始化y(1) 初始化z(x)
  2. 执行构造函数体,赋值x=100;

1586334077106

例子2

这个例子在网上很多博客都有,但是发现他们的解释全都错了!

class Weapon
{
private:
    string name;
    const string type;
    const string model;
public:
    Weapon(string& name, string& type, string& model) :name(name), type(type), model(model)
    {
        name = "Cloud";
    }
    string getProfile()
    {
        return "name: " + name + "
type: " + type + "
model: " + model;
    }
};

int main(void)
{

    string name = "Comet";
    string type = "carbine";
    string model = "rifle";
    Weapon weapon(name, type, model);
      cout << weapon.getProfile() << endl;

}

执行后的结果是

1586334182681

可以发现这和我们预期的是不一样的,不是应该name:Cloud吗??

网上其他的博客对此做出的解释“是注意观察,构造函数里的 name = "Cloud"; 被初始化列表的值覆盖了”

嗯..这其实是瞎扯淡..

再理一下顺序

  1. 执行初始化表name(name), type(type), model(model)
  2. 执行构造函数体name = "Cloud";

问题的所在就是构造函数体中的name其实是参数,而非Weapon类中的成员变量。我们稍作改变

	Weapon(string& nam, string& type, string& model) :name(nam), type(type), model(model)
	{
		name = "Cloud";
	}

发现这时候答案就和想象中的一样了

1586334429062

成员初始化表和构造函数体

 成员的初始化列表和构造函数在对成员指定初值方面是不一样的。成员初始化列表是对成员初始化,而构造函数,是对成员赋值

  • 成员初始化列表使用初始化的方式来为数据成员指定初值,
  • 而构造函数的函数体是通过赋值的方式来给数据成员指定初值。
  • 成员初始化列表是在数据成员定义的同时赋初值,
  • 但是构造函的函数体是采用先定义后赋值的方式来做。

这样就限制了,有些情况必须用成员初始化列表。

比如说

class A {
public:
	int m;
	A(int m1) :m(m1){}
};

class B {
public:
	int x;
	A a;
	B(int x1, int m1) :a(m1){ x = x1; }
};

这个例子中就必须使用a(m1)

因为A的构造函数被重写了,无参构造函数不存在,如果不使用初始化表方式对a进行初始化,默认会调用A(),但事实上没有这个构造函数,因此会报错。

但如果A有无参构造函数,则可以

class A {
public:
	int m;
	A(int m1) :m(m1){}
	A() { m = 0; }
};

class B {
public:
	int x;
	A a;
	B(int x1, int m1) { a = A(m1); x = x1; }
};

但是在这里,相当于a被初始化了两次,浪费了时间。

拷贝构造函数

拷贝构造函数的参数为什么必须使用引用类型

对于包含成员变量的类而言

  • 默认拷贝构造函数,调用成员对象的拷贝构造函数
  • 自定义拷贝构造函数,调用成员变对象的默认构造函数
void main() {
	B b1;
	cout << "b1.z:" << b1.z << "   b1.a.x:" << b1.a.x << "   b1.a.y:" << b1.a.y<<endl;
	b1.inc();
	cout << "b1.z:" << b1.z << "   b1.a.x:" << b1.a.x << "   b1.a.y:" << b1.a.y << endl;
	B b2(b1);
	cout << "b2.z:" << b2.z << "   b2.a.x:" << b2.a.x << "   b2.a.y:" << b2.a.y << endl;
}

case1

class A {
public:
	int x, y;
	A() {
		x = y = 0;
	}
	void inc() {
		x++;
		y++;
	}
};

class B {
public:
	int z;
	A a;
	B() { z = 0; }
	B(const B& b) { z = b.z; }
	void inc() {
		z++;
		a.inc();
	}
};

1586333049155

case2

class A {
public:
	int x, y;
	A() {
		x = y = 0;
	}
	void inc() {
		x++;
		y++;
	}
};

class B {
public:
	int z;
	A a;
	B() { z = 0; }
	B(const B& b) :a(b.a){ z = b.z; }
	void inc() {
		z++;
		a.inc();
	}
};

1586333094784

case3

class A {
public:
	int x, y;
	A() {
		x = y = 0;
	}
	void inc() {
		x++;
		y++;
	}
};

class B {
public:
	int z;
	A a;
	B() { z = 0; }
//	B(const B& b) :a(b.a){ z = b.z; }
	void inc() {
		z++;
		a.inc();
	}
};

1586333132997

原文地址:https://www.cnblogs.com/cpaulyz/p/12660895.html