初始化
在python 中创建实例对象的时候可以通过 init 方法对属性进行赋值, 而在 c++ 中也可以通过构建方法对属性初始化, 如:
class student{
string name;
int age;
/* 1
//早期的方式
student(string name_val , int age_val){
name = name_val;
age = age_val;
}
*/
//2
student(string name ,int age):name{name},age{age}{
cout << "执行有参构造函数" <<endl;
}
};
在一个类中包含了类名的方法就是构建方法, 它在创建实例对象时自动被调用,当实例对象有数据要初始化的时候可以在该构建方法中对属性赋值
委托构造
在c++中有重载这样的方法,所以,在创建实例对象的时候可以通过传参的不同进行调用不同的构造方法,所以,当实例对象无参的时候想要对属性进行初始化可以进行委托,就是无初始的构造方法调用有参数的构造方法,调用的时候有默认值:
class Student{
string name;
int age ;
public:
//无参构造 委托给两个参数的构造函数
Student():Student{"张三" , 19}{
};
//一个参数构造 委托给两个参数的构造函数
Student(string name_val):Student{name_val , 19}{
};
//由该函数完成最终的成员赋值工作
Student(string name_val , int age_val):name{name_val},age{age_val}{
};
};
委托就是无参委托有参,有参委托多参
析构函数
析构函数就是当实例对象将要删除的时候调用的方法, 如同python中的 del 方法, 可以在这个方法中写一些函数结束的处理工作
class Student{
string name;
int age ;
public :
//构造函数
Student(){
cout << "执行无参构造函数" <<endl;
}
Student(string name ){
cout << "执行含有一个参数的参构造函数" <<endl;
}
Student(string name , int age ){
cout << "执行含有两个参数的构造函数" <<endl;
}
//析构函{}
~Student(){
cout << "执行析构函数" <<endl;
}
};
在新对象 = 老对象 赋值的时候其实就是一个浅拷贝,如 stu s = stu的实例对象,这时候就是浅拷贝, 浅拷贝在赋值的时候其实是将原对象中的属性和方法复制一份给新的对象,不会走构造函数,而是走 拷贝函数:
class Student {
public:
int age ;
string name;
public :
//构造函数
Student(string name , int age ):name(name),age(age){
cout<< " 调用了 构造函数" << endl;
}
//拷贝构造函数
Student(const Student & s){
cout << "调用了拷贝构造函数" << endl;
age = s.age;
name = s.name;
}
//析构函数
~Student(){
cout << "调用了析构函数" << endl;
}
};
在不涉及堆内存的时候浅拷贝就够用了
深拷贝
当对象中有指针这种动态内存的时候浅拷贝就会出问题了,在新对象赋值创建的时候浅拷贝不会对指针内存进行拷贝,只会将属性也指向同一个内存, 当新对象对这个指针的数据进行修改的时候老对象中的数据也会发生改变,所以,当遇到这中情况的时候我们就要手动的创建堆内存了,
class Student {
public:
string name;
string *address;
Student(string name , string * address):name(name),address(address){
cout << "执行构造函数" << endl;
}
//深拷贝
Student(const Student & s){
cout << "调用了拷贝构造函数" << endl;
age = s.age;
name = s.name;
if(address == nullptr){
//开辟新的空间
address = new string();
*address = s.address;
}
}
//析构函数
~Student(){
cout << "调用了析构函数" << endl;
if(address != nullptr){
delete address;
address = nullptr;
}
}
};
在拷贝中手动的将指针类型的数据重新 new 一下,创建新的空间
什么时候会出现拷贝呢
在对象赋值的时候 stu s = 已有对象
在对象被当成参数的时候 void printStun(Student s)
;
在对象被当做函数返回值的时候 return s
返回值是对象的时候
当对象被当做返回值返回的时候其实会创建三个对象,一个是在函数的内部进行创建的,当这个函数结束的时候内存空间会被回收,又因为要返回一个对象,使用在返回的时候会复制一个新对象,作为临时对象,负责个调用这个函数接收的对象变量,加上这个赋值对象,一共有三个对象,一个构造,两个拷贝, 当然,编译器有时候为了避免拷贝生成临时对象而消耗内存空间,所以默认会有优化、避免发生过多的拷贝动作所以打印的日志可能不是我们所期望的,可以在cmake 中添加
# 如果使用cmake编译,可以添加配置
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-elide-constructors")
就可以观察到这三个对象了