/*
copy構造函數的調用 時機1 時機2
*/
#if 1
class Test4
{
public:
Test4() //無參數構造函數
{
m_a = 0;
m_b = 0;
cout << "我是構造函數,自動被調用了" << endl;
}
Test4(int a)
{
m_a = a;
m_b = 0;
}
Test4(int a, int b) //有參數構造函數 //3種方法
{
m_a = a;
m_b = b;
cout << "有參數構造函數" << endl;
}
//賦值構造函數 (copy構造函數) 作用完成對象的初始化
Test4(const Test4& obj)
{
cout << "我也是構造函數,我是通過另一個對象obj來初始化我自己 " << endl;
m_a = obj.m_a + 100;
m_b = obj.m_b + 100;
}
~Test4()
{
cout << "我是析構函數,自動被調用了" << endl;
}
public:
void printT()
{
cout << "普通成員函數" << endl;
cout << "m_a = " << m_a << ", m_b = " << m_b << endl;
}
private:
int m_a;
int m_b;
};
void test()
{
//賦值構造函數 用一個對象初始化另一個對象
Test4 t1(10, 12);
Test4 t0(0, 2);
//賦值操作 和 初始化是兩個不同的概念
//賦值 = 操作 不會調用拷貝構造函數,編譯器給我們提供的淺copy
t0 = t1; //用t1 給 t0賦值
//第一種 調用拷貝構造函數的時機
Test4 t2 = t1; //用t1來初始化t2,調用t2這個對象的拷貝構造函數
t2.printT();
//第二種 調用拷貝構造函數的時機
Test4 t3(t1); //用t1來初始化t2
t3.printT();
}
#endif
/*
賦值構造函數的調用 時機3
*/
#if 1
class Location
{
public:
//構造函數
Location(int xx = 0, int yy = 0)
{
X = xx;
Y = yy;
cout << "Constructor Object." << endl;
}
//拷貝構造函數 完成對象的初始化
Location(const Location &obj)
{
X = obj.X;
Y = obj.Y;
cout << "copy 構造函數." << endl;
}
~Location()
{
cout << X << "," << Y << " Object destroyed." << endl;
}
int GetX()
{
return X;
}
int GetY()
{
return Y;
}
private:
int X, Y;
};
//第三種 調用拷貝構造函數的時機
void f(Location p) //參數是一個元素
{
cout << p.GetX() << endl;
}
void test()
{
Location a(1, 2);
Location b = a; //第一種 調用拷貝構造函數的時機
/*
實參b去初始化形參p,c++編譯器會調用形參 p 這個對象的copy構造函數,
由於p是局部變量,函數f()運行完畢,p對象的生命週期結束,會調用
p對象的析構函數。
先創建的對象後釋放
*/
//b實參去初始化形參p,會調用copy構造函數
cout << "-------1------" << endl;
f(b); //第3種時機
cout << "-------2------" << endl;
cout << "b對象已經初始化完畢" << endl;
}
#endif
/*
賦值構造函數的調用 時機4
*/
#if 1
class Location
{
public:
//構造函數
Location(int xx = 0, int yy = 0)
{
X = xx;
Y = yy;
cout << "Constructor Object." << endl;
}
//拷貝構造函數 完成對象的初始化
Location(const Location &obj)
{
X = obj.X;
Y = obj.Y;
cout << "copy Constructor Object." << endl;
}
~Location()
{
cout << X << "," << Y << " Object destroyed." << endl;
}
int GetX() { return X; } int GetY() { return Y; }
private:
int X, Y;
};
//第4種 調用拷貝構造函數的時機
Location g()
{
Location A(11, 22);//執行對象A的構造函數
return A;
/*
return A;
這條語句 首先會創建一個匿名對象,用對象A初始化匿名對象,執行匿名對象的copy構造函數,
然後對象A的生命週期結束了,會執行對象A的析構函數。g()返回一個匿名對象.
*/
}
//測試匿名對象的生命週期
void objplay2()
{
g();//g()返回一個匿名對象,如果匿名對象沒人接,則會執行匿名對象的析構函數。
}
運行結果(測試匿名對象的生命週期)
/*
g()函數 返回一個元素
結論 1:函數的返回值是一個元素(複雜類型的),返回一個新的匿名對象(所以會調用匿名對象
的 copy構造函數)。
結論 2:有關匿名對象的去和留
如果用匿名對象 初始化 另一個同類型的對象,匿名對象轉化爲有名對象,匿名對象不會被析構掉
如果用匿名對象 賦值給 另一個同類型的對象,匿名對象被析構
*/
void objplay3()
{
//用匿名對象初始化m,此時c++編譯器直接把匿名對象轉成m(扶正),從匿名轉成有名對象了m
Location m = g();
printf("匿名對象,被扶正,不會被析構掉\n");
cout << m.GetX() << endl;
}
運行結果(函數返回的匿名對象的去初始化另一個對象)
void objplay4()
{
Location m2(1, 2);
m2 = g();//用匿名對象 賦值給 m2
printf("因爲用 匿名對象 賦值 給m2, 匿名對象被析構\n");
cout << m2.GetX() << endl;
}
運行結果(函數返回的匿名對象的去賦值另一個對象)
、
void objplay5()
{
//用匿名對象 賦值給 m2
Location m1(1, 2);
cout << "------1-----" << endl;
m1 = Location(33, 44); //賦值操作 Location(33, 44)會產生匿名對象,匿名對象被析構
cout << "------2-----" << endl;
Location m2 = Location(55, 66);//初始化操作 Location(55, 66)會產生匿名對象,匿名對象轉正,不會被析構
cout << "------3-----" << endl;
}
運行結果:
void objplay6()
{
Location(77, 88); //直接調用構造函數,會產生匿名對象,臨時匿名對象的生命週期
cout << "------1-----" << endl;
}
void test()
{
//objplay2();
//objplay3();
//objplay4();
//objplay5();
objplay6();
}
#endif