zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    【NOIP】提高组2015 神奇的幻方
    【BZOJ】1087: [SCOI2005]互不侵犯King
    【NOIP】提高组2005 过河
    【NOIP】提高组2012 借教室
    【vijos】P1083 小白逛公园
    【vijos】P1659 河蟹王国
    【vijos】P1448 校门外的树
    【vijos】P1066 弱弱的战壕
    【TYVJ】P1039 忠诚2
    【TYVJ】P1038 忠诚
  • 原文地址:https://www.cnblogs.com/cpaulyz/p/12660895.html
Copyright © 2011-2022 走看看