C++_构造函数、析构函数、对象初始化列表
发布时间:2022-11-11 12:01:44 261
相关标签:
构造函数
C++中的类可以定义与类名相同的特殊成员函数,这种函数叫构造函数
构造函数在定义时可以有参数或没有参数
没有任何返回类型的声明
析构函数
C++中的类可以定义一个特殊的成员函数清理对象,叫析构函数
语法:~calssname()
析构函数没有任何参数和返回类型的声明
析构函数在对象销毁时自动被调用
class test{
public:
test(){
a=10;
p=(char *)malloc(100);
strcpy(p, "abc");
cout<<"构造函数 被调用"<<endl;
}
~test(){
if (p!=NULL){
free(p);
}
cout<<"析构函数 被调用"<<endl;
}
private:
int a;
char *p;
};
void play(){
test t1, t2; //先创建的后释放
}
int main(){
play();
return 0;
}
构造函数的分类
默认无参构造函数:当类中没有定义构造函数时,会默认提供一个无参构造函数,函数体为空
默认拷贝构造函数:当类中没有定义拷贝构造函数,默认提供一个拷贝构造函数,简单的进行成员变量的赋值
class test{
public:
test(){ 无参构造函数
m_a=1;
m_b=2;
}
test(int a, int b){ 有参构造函数
m_a=a;
m_b=b;
}
test(const test& obj){ 拷贝构造函数
}
private:
int m_a, m_b;
};
int main(){
调用无参构造函数
test t1;
调用有参构造函数
test t2(); 错误
test t2(1, 2); 正确
对象的初始化和对象的赋值是两个不同的概念
t1=t2; 把t2赋值给t1
}
调用拷贝构造函数
class test{
public:
test(){
m_a=1;
m_b=2;
}
test(int a, int b){
m_a=a;
m_b=b;
}
void get(int a, int b){
m_a=a;
m_b=b;
}
test(const test& obj){
m_a=obj.m_a;
m_b=obj.m_b;
}
~test(){
}
private:
int m_a, m_b;
};
void func(test p){
p.get(1, 2);
}
test f(){
test t(1, 2);
return t; 用t返回一个匿名对象,调用匿名对象的拷贝构造函数,然后执行t的析构函数
}
int main(){
test t1(1, 2);
test t0(1, 2);
t0=t1; 用t1给t0赋值,不调用拷贝构造函数
调用t2的拷贝构造函数
test t2=t1;
调用t3的拷贝构造函数
test t3(t1);
t4实参取代p形参,会调用p的拷贝构造函数初始化p
func(t1);
因为f函数的返回值没有变量接,所以调用这个匿名对象的析构函数
f();
用匿名对象初始化t4, 把匿名对象转换成t4
test t4=f();
如果把f()赋值给一个初始化了的对象,则匿名对象被析构掉
t1=f(); 匿名对象被析构掉
}
构造函数调用规则
当类中定义了构造函数,C++编译器就不会提供无参构造函数
所以只要写了构造函数,就必须要用(可以写多个,用一个)
深拷贝和浅拷贝
class test{
public:
test(const char *myp){
len=strlen(myp);
p=(char *)malloc(len+1);
strcpy(p, myp);
}
test(const test& obj){
len=strlen(obj.len);
p=(char *)malloc(len+1);
strcpy(p, obj.p);
}
~test(){
if (p!=NULL){
free(p);
p=NULL;
len=0;
}
}
private:
char *p;
int len;
};
int main(){
//浅拷贝
test t1("abcde"); 在堆区为t1的p开辟内存空间
test t2=t1;
如果默认执行C++提供的拷贝构造函数,只是进行变量的简单赋值,将t2的p指向t1中的p指向的地址
后面的对象先析构,将t2中的p析构,之后析构t1中的p,但此时内存已经被析构掉,程序崩溃(野指针)
深拷贝
如果调用自己编写的拷贝构造函数,两次析构的不是同一块内存,不会出错
注意对象的赋值也是浅拷贝,需要重载=运算符
}
对象初始化列表
可以在初始化列表对成员变量进行初始化,
也可以在拷贝构造函数中通过初始化列表初始化变量
class A{
public:
A(int var){
a=var;
}
private:
int a;
};
class B{
public:
B(int var_b1, int var_b2, int var_a1, int var_a2):a1(var_a1), a2(var_a2), c(0){
b1=var_b1;
b2=var_b2;
}
private:
int b1;
int b2;
A a1;
A a2;
const int c;
};
int main(){
A(1);
B(1, 2, 3, 4);
return 0;
}
先执行组合对象的构造函数
如果组合对象有多个,按照 定义 的顺序,而不是按照初始化列表的顺序。
被组合对象的构造顺序和定义顺序有关系,与初始化列表顺序没有关系
析构函数的执行顺序和构造函数的调用顺序相反
文章来源: https://blog.51cto.com/u_15457669/5391351
特别声明:以上内容(图片及文字)均为互联网收集或者用户上传发布,本站仅提供信息存储服务!如有侵权或有涉及法律问题请联系我们。
举报