一、拷贝构造函数
1、拷贝构造函数是一种特殊的构造函数,就是用一个已有的对象去构造其同类的副本对象,即对象克隆。
1 class 类名 2 { 3 类名(类名& that) 4 { 5 对类成员挨个赋值 6 ... 7 } 8 } 9 10 class Student11 {12 char name[20];13 char sex;14 int age;15 public:16 Student(const char* _name,char _sex,int _age)17 {18 strcpy(name,_name);19 sex = _sex;20 age = _age;21 }22 Student(const Student& that)23 {24 strcpy(name,that.name);25 sex = that.sex;26 age = that.age;27 cout << "拷贝成功" << endl;28 }29 };
2、编译器会默认生成一个拷贝构造函数,如果自定义拷贝构造函数,就只能定义一个,拷贝构造函数不能重载。
3、一般调用拷贝构造函数的情况:
a、对象与对象赋值
b、用对象与函数传参
c、用对象当返回值
二、初始化列表
1、初始化列表是一种成员的初始化方式,在构造函数的大括号前使用小括号对类的成员进行初始化的一种方式
1 class 类名 2 { 3 类名(参数列表):成员1(参数1),成员2(参数2) 4 { 5 6 } 7 } 8 9 class Student10 {11 char name[20];12 char sex;13 const int age;14 public:15 Student(const char* _name,char _sex,int _age):age(_age)16 {17 strcpy(name,_name);18 sex = _sex;19 //age = _age;20 }21 22 Student(const Student& that):age(that.age)23 {24 strcpy(name,that.name);25 sex = that.sex;26 //age = that.age;27 cout << "拷贝成功" << endl;28 }29 };
2、参数列表可以解决构造函数参数与成员重名的问题,参数列表会先于构造函数执行,如果成员中有const成员、引用成员,必须使用初始化列表进行初始化
三、this指针
1、为了让成员函数知道是哪个对象在调用,并准确访问到对象的成员,编译器会自动为每个成员函数添加一个看不到的参数,这个参数就是指向调用对象的指针(this)。
2、类中的所有成员函数都有this指针,包括构造、析构、拷贝构造等。
3、this指针默认情况下都是隐藏的(在成员函数中访问成员变量时自动就加上了),但也可以显示使用。
四、常对象与常函数
1、创建对象时添加const关键字,这个对象就不可再修改,就有了常属性,就意味着整个对象中的所有东西都不能修改。
2、常对象不能调用普通成员函数,调用成员函数就相当于把对象的this指针给了它,就会有被修改的风险。
3、函数体前加const关键的叫常函数,常对象只能调用常函数,普通对象也可以调用常函数。
常函数就相当于对this指针添加了cosnt属性。
4、常函数与'非'常函数会形成重载不会冲突。
5、如果有成员确实需要修改,它又需要被const修饰,可以对成员添加一个关键字mutable,这样即使常对象调用了常函数依然可以修改成员。
五、构析函数
1、当对象被销毁时自动调用的函数叫构析函数,对象的整个生命周期中只能被调用一次,他是对象被销毁前最后执行的动作
1 class 类名2 {3 // 不能重载、只能有一个4 // 没有返回值、没有参数 5 ~类名(void)6 {7 8 }9 }
2、编译器会默认产生一个构析函数,默认构析函数负责销毁能看到的成员,成员的构析与构造过程相反
3、当类中有析构造函数看不到的资源时(new/malloc)、有需要还愿的设置时(把打开的文件关闭/把获取到的数据保存),这时就需要自定义析构函数。
六、赋值构造 1、赋值构造就是一个对象给另一个对象赋值的时候调用的函数。
1 stu2 = stu1; // 赋值构造 2 3 Student stu2 = stu1;// 拷贝构造 4 5 void func(Student stu);// 拷贝构造 6 func(stu1); 7 8 Student func(void) // 拷贝构造 9 {10 return *this;11 }12 Student stu = func()
2、赋值构造函数的格式
1 void operator = (Student& that) 2 { 3 4 } 5 6 // 可以与其它对象进行交互 7 Student& operator = (Student& that) 8 { 9 10 }
3、赋值构造也拷贝构造的区别
拷贝构造:使用对象A去创建出对象B(调用时对象B还末生成)。
赋值构造:对象A与对象B都已经构造完成,此时B = A;
如果对象中有常成员拷贝构造可以成功调用,但赋值构造不行。
4、
1 void operator = (Student& that) 2 { 3 if(this == &that) return; 4 // 释放旧资源 5 delete[] name; 6 Student(that); 7 // 申请新资源 8 name = new char[strlen(that.name)+1]; 9 // 拷贝新内容10 strcpy(name,that.name);11 sex = that.sex;12 age = that.age;13 }
七、静态成员与静态成员函数
1、成员被static修饰后,就会存储在bss段(此段是由编译存放的而且大小固定),在程序中动态的创建对象时它的静态成员就无法创建,所有的类对象共享一个静态成员。
2、静态成员只能在类中声明不能类中定义(必须在类外定义)
3、静态成员就是声明在类中的全局变量,在任何位置都可以使用
4、静态成员函数,类中的成员函数被static修饰后就变成了静态成员函数,所有对象共享一份静态成员函数。
5、静态成员函数不会传递this指针,也就不能访问成员变量。
1 class Student 2 { 3 char name[20]; 4 char sex; 5 short age; 6 public: 7 static int room; 8 Student(const char* _name="",char _sex='f',short _age=1) 9 {10 strcpy(name,_name);11 sex = _sex;12 age = _age;13 }14 void show(void)15 {16 cout << name << " " << sex << " 教室编号:"17 << room << &room<< endl;18 }19 static void func(Student& stu)20 {21 cout << stu.name << " " << stu.sex << " 教室编号:"<< stu.room << endl;22 23 }24 };25 26 int Student::room = 180602;
八、单例模式
1、只能创建出一个对象的类叫做单例类,这种模式叫单例模式
2、单例模式的商业应用:网站计数器、日志管理系统、连接池、线程池、内存池
1 饿汉单例模式 2 不管是否需要对象都已经创建好了。 3 优点:效率高、速度快、稳定。 4 缺点:浪费资源,不管需不需要对象都已经创建好; 5 class Singleton 6 { 7 static Singleton intance; 8 Singleton() 9 {10 11 }12 Singleton(Singleton& that)13 {14 15 }16 void operator = (Singleton& that)17 {18 19 }20 public:21 static Singleton& getIntance(void)22 {23 return intance;24 }25 };26 27 Singleton Singleton::intance;
1 懒汉单例模式 2 当首次使用获取对象时才会真正创建出对象。 3 优点:节约资源 4 缺点:效率低,速度慢,不安全(多线程情况下)。 5 class Singleton 6 { 7 static Singleton* intance; 8 Singleton() 9 {10 11 }12 Singleton(Singleton& that)13 {14 15 }16 void operator = (Singleton& that)17 {18 19 }20 public:21 static Singleton& getIntance(void)22 {23 if(NULL == intance)24 {25 intance = new Singleton;26 }27 return *intance;28 }29 ~ Singleton(void)30 {31 delete intance;32 }33 };34 35 Singleton* Singleton::intance = NULL;