浅拷贝:简单的拷贝赋值操作
深拷贝:在堆区重新开辟空间,进行拷贝操作
下面举例解释:
创建person类与测试函数
class person
{
public:
person()
{
cout << "person默认构造函数调用" << endl;
}
person(int age, int height)
{
m_age = age;
m_height = new int(height);
cout << "person有参构造函数调用" << endl;
}
~person()
{
cout << "person析构函数调用" << endl;
}
int m_age;
int* m_height;
};
void test01()
{
person p1(22,179);
cout << "年龄为" << p1.m_age << "身高为" << *p1.m_height << endl;
person p2(p1);
cout << "年龄为" << p2.m_age << "身高为" << *p2.m_height << endl;
}
此时p1/p2的各个属性都是相同的
而此时,由于属性中m_height是我们new出的堆区的数据,需要我们手动释放,因此我们在析构函数中写出释放的部分
~person()
{
if (m_height != NULL)
{
delete m_height;
m_height = NULL;
}
cout << "person析构函数调用" << endl;
}
再次运行
程序直接崩了
因为编译器自己的拷贝构造函数是浅拷贝操作
浅拷贝带来的问题就是堆区内存重复释放
因此,使用深拷贝解决,我们自己创建一块堆区保存数据,即自己实现拷贝构造函数
person(const person& p)
{
m_age = p.m_age;
//m_height = p.m_height; //编译器默认实现,即浅拷贝
m_height = new int(*p.m_height);
cout << "person拷贝构造函数调用" << endl;
}
成功实现
总结:如果属性有在堆区开辟的,自己要提供拷贝构造函数,防止浅拷贝带来问题
语法:
构造函数() : 属性1(值1),属性2(值2),属性3(值3)...
{
;
}
例:
一般情况下,我们初始化是创建对象同时赋值
class person
{
public:
person(int a, int b, int c)
{
m_a = a;
m_b = b;
m_c = c;
}
int m_a;
int m_b;
int m_c;
};
void test01()
{
person p(10, 20, 30);
cout << p.m_a << endl;
cout << p.m_b << endl;
cout << p.m_c << endl;
}
接下来使用初始化列表的方式初始化值
class person
{
public:
person() :m_a(30), m_b(20), m_c(10)
{
;
}
int m_a;
int m_b;
int m_c;
};
void test01()
{
person p;
cout << p.m_a << endl;
cout << p.m_b << endl;
cout << p.m_c << endl;
}
这样就实现了列表初始化值,不过这样初始化的值是固定的,可以进一步优化
例
创建2个类:person类与car类,在person中定义2个属性,1个是人名,1个是车名,而车名来自于car类
class car // 车类
{
public:
car(string car)
{
c_car = car;
cout << "car的执行" << endl;
}
string c_car;
};
class person // 人类
{
public:
person(string name, string c_car) :m_name(name), m_car(c_car)
{
cout << "person的执行" << endl;
}
string m_name;
car m_car;
};
void test01()
{
person p("Joyce", "BMW");
cout << p.m_name << "开着" << p.m_car.c_car << endl;
}
int main()
{
test01();
return 0;
}
而两个类,哪个先执行,哪个先销毁?
class car
{
public:
car(string car)
{
c_car = car;
cout << "car的执行" << endl;
}
~car()
{
cout << "car析构的执行" << endl;
}
string c_car;
};
class person
{
public:
person(string name, string c_car) :m_name(name), m_car(c_car)
{
cout << "person的执行" << endl;
}
~person()
{
cout << "person析构的执行" << endl;
}
string m_name;
car m_car;
};
总结:
静态成员变量 | 所有对象共享同一份数据 |
在编译阶段分配内存 | |
类内声明,类外初始化 | |
静态成员函数 | 所有对象共享同一个函数 |
静态成员函数只能访问静态成员变量 |
class person
{
public:
static int m_age;
};
void test01()
{
person p;
cout << p.m_age << endl;
}
int main()
{
test01();
return 0;
}
简单创建p,尝试运行p中的静态成员变量,会直接报错,因为编译不过去
// ①通过对象进行访问
person p;
cout << p.m_age << endl;
// ②通过类名进行访问
cout << person::m_age << endl;
这时需要加上类外初始化
类外随便加一句
int person::m_age = 52;
同时,静态成员变量有2种访问方式
①通过对象进行访问
②通过类名进行访问
// ①通过对象进行访问
person p;
cout << p.m_age << endl;
// ②通过类名进行访问
cout << person::m_age << endl;
而对象访问这里我们再创建一个变量,即可验证静态成员变量共享同一块数据
void test02()
{
// ①通过对象进行访问
person p;
cout << p.m_age << endl;
person p2;
p2.m_age = 66;
cout << p.m_age << endl;
}
2次都输出p.m_age
同时,静态成员变量也有访问权限
class person
{
private:
int m_a;
};
int person::m_a = 22;
尝试cout输出
整体与静态成员变量规则相同,只不过在函数前加上static
class person
{
public:
static void func()
{
m_a = 55;
cout << "func的调用" << endl;
}
static int m_a;
};
int person::m_a = 50;
void test01()
{
// 通过对象访问
person p;
p.func();
// 通过类名访问
person::func();
}
int main()
{
test01();
return 0;
}
不过,首先静态成员函数只能访问静态成员变量
class person
{
public:
static void func() // 静态成员函数
{
m_a = 55;
m_b = 10;
cout << "func的调用" << endl;
}
static int m_a; // 静态成员变量
int m_b; // 普通成员变量
};
直接报错
同时,静态成员函数也有访问权限
class person
{
private: // 私有权限
static void func2() // 静态成员函数
{
cout << "func2的调用" << endl;
}
};
不可访问