目录
五、深拷贝和浅拷贝(如果有属性在堆区开辟,一定要自己创建拷贝构造函数,防止浅拷贝带来的问题)
一、对象的初始化和清理
1.构造函数 -- 进行初始化操作
语法:类名 (参数类型) {}
构造函数的特点:
(1)没有返回值,也不用写void
(2)函数名与类相同
(3)构造函数可以有参数,可以发生重载
(4)创建对象的时候,构造函数会自动调用,而且只调用一次
这就是自动调用
2.析构函数 -- 进行清理的操作
语法:~类名 () {}(析构函数不可以有参数)
析构函数的特点:
(1)没有返回值,不用写void
(2)函数名和类名相同,在函数名前面加~
(3)析构函数不可以有参数,不能发生重载
(4)对象在销毁前会自动调用析构函数,而且只会调用一次
如果没有创建构造函数和析构函数,编译器会自动产生,相当于
二、构造函数的分类和调用方法
构造函数的分类:
1.有参函数和无参函数(无参构造也称为默认构造)
(除了默认构造函数外其他都是有参函数)
2.普通函数和拷贝函数(除了拷贝函数外其他都是普通函数)
什么是拷贝函数?
Person(const Person& p)
{
//将传入人的所有属性都拷贝到我身上来
Age = p.Age;//p.Age是传入的数值
cout << "拷贝构造函数的调用" << endl;
}
三种调用方式:
注意事项:
1.无参构造函数的调用函数名后不需要加( );加了( )会被识别为函数声明
2.显示法中的Person(10)是匿名对象,当执行结束后,系统会立即回收
3.不能用拷贝构造函数初始化匿名对象如:Person (p3);编译器会将其理解为是Person p3;
三、拷贝构造函数的调用时机
1.使用一个已经创建完毕的对象初始化一个新对象
2. 以值传递的方式给函数参数传值
3.值方式返回局部对象
四、构造函数调用规则
1.创建一个类,C++编译器至少会给每个类添加至少3个函数
(1)默认构造函数(空实现)
(2)析构函数(空实现)
(3)拷贝构造(值拷贝)
但如果你自己创建了构造函数,拷贝函数,则编译器就会采用你创建的函数
五、深拷贝和浅拷贝(如果有属性在堆区开辟,一定要自己创建拷贝构造函数,防止浅拷贝带来的问题)
浅拷贝:简单的赋值拷贝操作
#include<iostream> using namespace std; class Person { public: Person() { cout << "无参构造函数的调用" << endl; } Person(int age, int weight) { cout << "有参构造函数的调用" << endl; m_age = age; m_weight = new int(weight);//new在开辟堆区空间,返回int* } Person(const Person& p) { cout << "拷贝构造函数的调用" << endl; m_age = p.m_age; m_weight = p.m_weight; } ~Person() { cout << "析构函数的调用" << endl; //释放堆区空间一般在析构函数中 if (m_weight != NULL) { delete m_weight; } } public: int m_age; int* m_weight; }; void test01() { Person p1(16, 50); Person p2(p1); cout << "p1的年龄是:" << p1.m_age << endl; cout << "p2的年龄是:" << p2.m_age << endl; cout << "p1的体重是:" << *p1.m_weight << endl; cout << "p2的体重是:" << *p2.m_weight << endl; } int main() { test01(); system("pause"); return 0; }
堆区内存重复释放问题?
拷贝构造函数的m_weight 和有参构造函数的m_weight指向的都是同一块空间,堆区的规则是:先进后出,所以拷贝构造函数对应的析构函数先执行释放操作,释放完后才轮到有参构造函数对应的析构函数执行释放操作,但是这块空间已经被拷贝构造函数的对应的析构函数释放,所以有参构造函数想再执行释放操作就是重复释放
深拷贝: 在堆区重新申请一块空间,进行拷贝操作
先*进行解引用,就会变成具体的数据,然后在根据类型在堆区开辟空间
六、初始化列表
1.初始化列表给属性初始化
语法:构造函数 () :属性1(值1), 属性2(值2), 属性3(值3) { }
#include<iostream> using namespace std; 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; }; int main() { Person p(10, 11, 12); cout << p.m_a << endl; cout << p.m_b << endl; cout << p.m_c << endl; system("pause"); return 0; }
七、类对象作为类成员
例如:
class A
{ };
class B
{
A a;
};
B类中有对象A作为成员,A为对象成员
A和B的构造和析构谁先谁后?
Phone是对象成员
#include<iostream> using namespace std; #include<string> //手机类 class Phone { public: Phone(string name) :PName(name) { cout << "Phone的构造函数" << endl; } ~Phone() { cout << "Phone的析构函数" << endl; } string PName; }; //人类 class Person { public: Person(string name1, string name2):M_Name(name1),M_phone(name2) { cout << "Person的构造函数" << endl; } ~Person() { cout << "Person的析构函数" << endl; } void Show() { cout << M_Name << "拿着" << M_phone.PName << endl; } string M_Name; Phone M_phone; }; void test() { Person p("张三", "iqoo"); p.Show(); } int main() { test(); system("pause"); return 0; }
八、静态成员
1.静态成员变量
特点:
(1)所有对象共享同一份数据
(2)在编译阶段分配内存
(3)类内声明,类外初始化
注意:静态成员变量也有访问权限
#include<iostream> using namespace std; class Person { public: //静态成员变量,类内声明 static int m_A; private: //静态成员变量也有访问权限 static int m_B; }; //类外初始化 int Person::m_A = 100; //int Person::m_B = 200; void test() { Person p; //通过对象访问 cout << p.m_A << endl; p.m_A = 200; //通过类名 cout << Person::m_A << endl; //cout << p.m_B << endl; } int main() { test(); system("pause"); return 0; }
静态成员变量有两种访问方式
(1)通过对象
(2)通过类名
2.静态成员函数
特点:
(1)所有对象共享同一个函数
(2)静态成员函数只能访问静态成员变量
注意:静态成员变函数也有访问权限
访问方式也有两种和静态成员变量一样