构造函数和析构函数执行的顺序
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
using namespace std;
class Test{
public:
Test(char * name){
memset(this->name,0,sizeof(this->name));
strcpy(this->name,name);
cout<<"Test()->Name = "<<name<<endl;
}
~Test(){
cout<<"~Test()->Name = "<<name<<endl;
}
protected:
private:
char name[64];
};
void run()
{ //#1
Test t1("t1");
Test t2("t2");
} //#2
void run2()
{//#1
Test t1("t1");
}//#2
int main(int argc, char *argv[])
{ run2()// #1 -> t1的构造函数 -> #2 -> t1的析构函数
run();// #1 -> t1的构造函数 -> t2的构造函数 -> #2 -> t2的析构函数 -> t1的析构函数
return 0;
}
构造函数的调用时机
#include <iostream>
using namespace std;
class Test{
public:
//构造函数分类:无参,有参和拷贝
//无参构造函数
Test(){
cout<<"Test(void)"<<endl;
};
//带参构造函数
Test(int a){
cout<<"Test(int )"<<endl;
}
Test(int a,int b){
cout<<"Test(int ,int )"<<endl;
}
//拷贝构造函数
Test (const Test &object){
cout<<"Test(const Test & )"<<endl;
}
};
int main(int argc, char *argv[])
{
//如果类没有提供构造函数,C++会默认提供一个无参构造函数和一个拷贝构造函数
//调用无参构造函数
Test t1;//OK
// Test t1(); //Error
//调用带参构造函数
Test t2(5);//OK
Test t3 = (4,5);//OK ==> (4,5)会被当成逗号表达式,最终调用的其实是 Test(int),若是不存在[Test(int)]则编译器报错
//使用匿名对象调用构造函数
Test t4 = Test(1,2); //OK ==> Test(int ,int)
//调用拷贝构造函数
Test t5(10,20);
Test t6 = t5;//调用的是拷贝构造函数
Test t7(t5);//调用的是拷贝构造函数
Test one,two;
one = two;//调用的是赋值函数,没有调用构造函数
return 0;
}
拷贝构造函数的调用时机
#include <iostream>
using namespace std;
class Location{
private:
int x;
int y;
public:
Location(){
cout<<"Test()"<<endl;
}
~Location(){
cout<<"~Test()"<<endl;
}
Location(int x,int y){
cout<<"Location(int ,int )"<<endl;
this->x = x;
this->y = y;
}
Location (const Location & location){
this->x = location.x;
this->y = location.y;
cout<<"Location(const Location & location)"<<endl;
}
public:
void show(){
cout<<"x = "<<x<<" y = "<<y<<endl;
}
};
void copy(Location L)//传参过程执行的是拷贝构造函数
{ //#1
L.show();
} //#2
void run()
{ //#1
Location L_one(100,200); //#2
copy(L_one); //#3
} //#4
/*
run函数
run#1 -> run#2:L_one的构造函数 -> run#3:copy(L_one)[L_one执行拷贝构造函数] -> copy:#1 -> copy#2:L的析构函数 -> run#4:L_one的析构函数
*/
//当函数的返回值是一个类的类型的时候[类的类型,仅指(Location),并非(Location * 或 Location &)],函数 return 的时候也会执行拷贝构造函数
//这里仅指VS2012的编译器,GCC并不支持这一做法
Location getLocation()
{ //#1
Location Lo(7,8);
return Lo; //#2 //函数的返回值是一个元素(class),C++编译器会返回以一个新的匿名对象
} //#3
void run2(){ //#1
getLocation(); // 函数返回的时候没有(Location)对象被接收 -> "[匿名Location对象]~Test()"
} //#2
/*
run2函数
VS2013:
run2#1: -> getLocation#1 -> getLocation#2[
1):Lo执行拷贝构造函数 Test(cosnt Test &) 创建一个匿名的Location对象.
2):Lo执行析构函数 ~Test()
] -> getLocation#3: 返回匿名Location对象 -> run2#2:匿名Location对象执行析构函数 ~Test()
QT5.7:
run2#1: -> getLocation#1 -> getLocation#2 -> getLocation#3: 返回自身(Lo对象) -> run2#2:Lo 对象执行析构函数 ~Test()
*/
void run3(){ //#1
Location LoL = getLocation();//#2 // 函数返回时有匿名对象接收 -> C++编译器会把匿名对象直接转成LoL,并不会执行拷贝构造函数
LoL.show();
} //#3
/*
run3函数
VS2013:
run3#1: -> getLocation#1 -> getLocation#2[
1):Lo执行拷贝构造函数 Test(cosnt Test &) 创建一个匿名的Location对象.
2):Lo执行析构函数 ~Test()
] -> getLocation#3: 返回匿名Location对象 -> run3#2:匿名Location对象直接转成LoL对象(不执行拷贝构造函数)
-> run3#3:LoL执行析构函数 ~Test()
QT5.7:
run3#1: -> getLocation#1 -> getLocation#2 -> getLocation#3: 返回自身(Lo对象) -> run3#2:Lo 对象直接转成LoL对象(不执行拷贝构造函数) -> run3#3:LoL执行析构函数 ~Test()
*/
void run4(){ //#1
Location Lol(4,5); //对象已经初始化
Lol.show();
Lol = getLocation(); //#2 //匿名对象会执行赋值操作直接复制给(Lol)然后执行析构函数
Lol.show();
} //#3
/*
run4函数
VS2013:
run4#1: -> getLocation#1 -> getLocation#2[
1):Lo执行拷贝构造函数 Test(cosnt Test &) 创建一个匿名的Location对象.
2):Lo执行析构函数 ~Test()
] -> getLocation#3: 返回匿名Location对象
-> run4#2:匿名Location对象直接将值复制给(Lol),然后执行析构函数 ~Test()
-> run4#3:Lol执行析构函数 ~Test()
QT5.7:
run4#1: -> getLocation#1 -> getLocation#2 -> getLocation#3: 返回自身(Lo对象) -> run4#2:Lo 对象直接将值直接复制给(Lol)然后执行析构函数 ~Test()
-> run4#3:LoL执行析构函数 ~Test()
*/
int main(int argc, char *argv[])
{
// run();
// run2();
// run3();
// run4();
return 0;
}
C++中的浅拷贝
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
using namespace std;
class Name{
public:
Name (const char * name){
this->length = strlen(name);
this->name = (char *)malloc(this->length + 1);
strcpy(this->name,name);
}
~Name(){
if (this->name != NULL){
free(this->name);
this->name = NULL;
this->length = 0;
}
}
//解决方案:
/*
Name (const Name & N){
this->length = N.length;
this->name = (char *)malloc(this->length + 1);
strcpy(this->name,N.name);
}
*/
public:
void show(){
cout<<"Name = "<<this->name<<endl;
}
private:
char * name;
int length;
};
void run(){
Name N_1("yzh"); // N_1执行构造函数初始化
{
Name N_2 = N_1;
// 在没有 [解决方案] 的前提下
/*
N_2执行Name类默认的拷贝构造函数来初始化(浅拷贝),则
N_2的成员变量Name并未重新分配内存,而是指向了N_1的Name所在的内存,即N_1的Name和N_2的Name指向的是同一片内存
当程序执行到[ #2 ]处的时候,N_2执行析构函数,N_2的Name所处的内存被回收
当在[ #2 ]之后再次执行[ N_1.show(); ]的时候,会因为内存已经被回收而导致程序出现错误
*/
N_1.show();
N_2.show(); //Name = yzh;
}//#2
N_1.show(); // 不存在[解决方案]的时候 Name = 垃圾值
}
int main(int argc, char *argv[])
{
run();
return 0;
}
构造函数初始化列表:
1)B类中组合了A类对象
2)A类设计了构造函数
#include <iostream>
using namespace std;
class A{
public:
A(int a){
cout<<"A = "<<a<<endl;
this->a = a;
}
~A(){
cout<<"~A = "<<a<<endl;
}
private:
int a;
};
//B类中含有A类的对象
class B{
public:
//利用B类构造函数的初始化列表来初始化A类
B(int a,int b):A_two(b),A_one(a) //初始化列表顺序
{
this->a = a;
this->b = b;
cout<<"B"<<endl;
}
~B(){
cout<<"~B"<<endl;
}
private:
int a;
int b;
//定义的顺序
A A_one;
A A_two;
};
void run(){
B b(1,2);
/*
1)按照定义的顺序通过构造函数列表执行A类的构造函数,A类的构造函数执行完毕之后才是B类的构造函数
2)构造函数的执行顺序和析构函数执行的顺序相反
A_one构造函数 -> A_two构造函数 -> B 的构造函数 -> B 的析构函数 -> A_two的析构函数 -> A_one的析构函数
*/
}
int main(int argc, char *argv[])
{
run();
return 0;
}
构造函数列表执行顺序
#include <iostream>
using namespace std;
class A{
public:
A(int a,int b){
this->a = a;
this->b = b;
cout<<"A = "<<a<<" B = "<<b<<endl;
}
~A(){
cout<<"~A"<<endl;
}
private:
int a;
int b;
};
class B{
public:
B(int a,int b):A_1(a,b),A_2(a,b),m(b),n(a)
{
cout<<"M = "<<m<<" N = "<<n<<endl;
}
B(const B & sb):A_1(sb.m,sb.n),A_2(sb.n,sb.m)
{
this->m = sb.m;
this->n = sb.n;
cout<<"B (const B &)"<<endl;
}
~B(){
cout<<"~B"<<endl;
}
public:
void show(){
cout<<"SHOW: M = "<<m<<" N = "<<n<<endl;
}
private:
int m;
int n;
A A_1;
A A_2;
};
void getShow(B sb){
sb.show();
}
void run(){
B sb(22,99);
getShow(sb);
}
int main(int argc, char *argv[])
{
run();
/*
//从B的普通构造函数进入
A = 22 B = 99 A_1构造
A = 22 B = 99 A_2构造
M = 99 N = 22 sb构造
//从B的拷贝构造函数进入
A = 99 B = 22 A_1构造
A = 22 B = 99 A_2构造
B (const B &) sb的拷贝构造
SHOW: M = 99 N = 22 sb的show函数
//析构函数逆序执行
~B
~A
~A
~B
~A
~A
*/
return 0;
}
匿名对象的生命周期
#include <iostream>
using namespace std;
class Test{
public:
Test(){
cout<<"Test"<<endl;
}
~Test(){
cout<<"~Test()"<<endl;
}
};
void run(){
cout<<"#1"<<endl;
Test();//初始化一个匿名对象
cout<<"#2"<<endl;
Test t;//初始化一个名为t的对象
// Test t();//Error
cout<<"#3"<<endl;
}
/*
#1 -> "Test()" -> "~Test()" -> #2 -> "Test()" -> #3 -> "~Test()"
//匿名对象会在 #2 之前被析构掉
//t对象会在run函数的"}"结束之后被析构掉
*/
int main(int argc, char *argv[])
{
run();
return 0;
}
构造函数调用构造函数
#include <iostream>
using namespace std;
class Test{
public:
Test(int a,int b){
this->a = a;
this->b = b;
Test(a,b,100); //产生一个匿名对象,构造之后马上被析构掉了,根本无法为变量c赋值
}
Test(int a,int b,int c){
this->a = a;
this->b = b;
this->c = c;
}
~Test(){
cout<<"~Test()"<<endl;
}
public:
void show(){
cout<<"SHOW: A = "<<a<<" B = "<<b<<" C = "<<c<<endl;
}
private:
int a;
int b;
int c;
};
void run(){
Test t(1,2);
t.show(); //c是一个垃圾值
}
int main(int argc, char *argv[])
{
run();
return 0;
}