一. 拷贝构造函数(重点)
1.系统会自动生成浅拷贝方法:
浅拷贝构造函数的条件:
使用一个对象去初始化另一个对象
2.自己重写拷贝构造函数方法
在构造函数传递一个参数是类的引用,那么这个构造函数就是重写之后的拷贝构造函数
语法:
C++ class 类名{ public: //重写拷贝构造函数 类名(类名 &a){ } } //---------------------- class base{ public: base(base &a){ } }
注意:
当用户自己重写拷贝构造函数之后,系统就不会再自动调用浅拷贝构造方法
C++ //重写拷贝构造函数 参数是 类的引用 base(base &a) { cout << "这是我自己重写的拷贝构造函数" << endl; //初始化 (相当于是o1对象的成员的值 赋值给 o2对象的成员) this->x = a.x; this->y = a.y; }
以上结果看起来和浅拷贝没有什么区别,那为什么不能浅拷贝,而要深拷贝????
举例:
C++ #include <iostream> using namespace std; extern "C"{ #include <string.h> } class base{ public: base(const char * str){ //分配空间 p = new char[100]; //赋值字符串 strcpy(p,str); } void show(){ cout << "堆空间的地址:" <<(void *) p << endl; cout << "内容" << p << endl; } char * p; }; int main(int argc, char const *argv[]) { base a("hello~"); a.show(); //用a对象初始化对象b -- 自动调用系统浅拷贝构造方法 base b = a; b.show(); //成员中如果有指针类型 //因为浅拷贝是直接复制赋值 //两个对象中的指针指向相同地址 内容也相同 //导致修改一个对象的内容,另一个对象也会发生改变 cout << "------修改b,输出a------" << endl; //修改b中p的内容 strcpy(b.p,"world~"); //输出a的内容,发现 也发生了改变 a.show(); return 0; }
所以需要重写拷贝构造函数
练习深拷贝:
C++ #include <iostream> using namespace std; extern "C"{ #include <string.h> } class new_base{ public: new_base(const char * str,int size): size(size){ p = new char[size]; strcpy(p,str); } new_base(new_base &a){ //初始化size this->size = a.size; //分配内存 p = new char[this->size]; //拷贝指针指向的内容 strcpy(p,a.p); } void show(){ cout << "地址" << (void *) p << endl; cout << "内容" << p << endl; } //显示接口 private: char * p; //指向堆空间的指针 int size; //分配堆空间的大小 }; int main(){ //定义对象 new_base a("哈哈哈",100); a.show(); //调用深拷贝 new_base b = a; b.show(); }
总结:如果对象中数据成员里有指针类型,必须自己重写拷贝构造函数(深拷贝)
二.类外定义类中成员函数(接口)
语法:
返回值类型 类名::函数名(参数){
}
举例:
C++ class base{ public : //类内--函数声明 void show(); } //类外--函数定义 int base::show(int a){ cout << a << endl; return a; }
三.类的继承
继承作用:
提高代码的复用性
有利于软件版本的升级
继承定义:
从父类中获取一些数据成员或函数接口, 如果该成员是共有的或者受保护成员,则子类可以直接访问,提高代码的复用性
C++ class Person{ public : int id; //身份证号码 char * name[40]; //名字 double money; //资产 } //不继承 代码重复编写 class stu{ private: int grade; } //不继承 代码重复编写 class teacher{ public : int id; //身份证号码 char * name[40]; //名字 double money; //资产 private: char * sick[1024]; } A: 人脸数据采集 功能 A ----> 嘎了 走了 B: 人脸数据模型训练 继承 A C: 人脸识别 继承A
继承语法:
C++ class 子类名: 继承方式 基类名 { //添加派生类的成员(子类成员) }
C++ //定义person基类 class person{ public: int age; double money; }; //定义一个singer派生类 class singer:public person{ //新增singer的数据 private: int songs; int concerts; };
父类 也叫基类
子类 也叫派生类
总结:
如果派生类想要访问基类中私有成员,只能在基类中设置接口让派生类访问
四.继承
1. 语法:
C++ class 类名:继承方式 基类名{ //派生类自己的成员 } class son:public father{ //son的成员 }
父类--基类
子类--派生类
2. 继承访问权限的问题:
派生类继承基类后,可以访问基类中的受保护成员和公有成员
如果想要访问基类中的私有成员,只能在基类中设计接口,让派生类来间接访问
3. 继承方式:影响的是类外函数对基类成员的访问权限
public: 公有形式: 在派生类中保持基类原有的数据成员的访问权限(类外依然可以访问公有成员--常用)
private:私有形式:在派生类中将基类访问权限全部改为private私有(只有类内可以访问,类外都无法访问--偶尔用于细节控制)
protected:保护形式:在派生类中将基类中public公有变为protected保护成员(类外无法访问--基本不用)
练习:分析访问权限
C++ class base{ public: int a; int get_c(){ return c; } protected: int b; private: int c } class new_base:public base{ public: void set(int a,int b){ this->b = a+this->get_c(); this->a = b++; } } //类外无法访问 保护成员b 私有成员c void test(base &a){ a.b = 10; a.c = 20; }
4. 给基类成员初始化
派生类中使用初始化列表 给基类进行初始化
C++ class base{ public: base(int a,int b):a(a),b(b){ cout << "初始化成功:" << a << "----" << b << endl; } private: int a; int b; }; //派生类 class new_base:public base{ public: //利用参数列表 a1和b1是参数 // 直接将基类中的成员a b放到初始化列表中---不可以(和ab的访问权限没关系) // new_base(int a1,int b1):a(a1),b(b1){} //将a1和b1传入到base基类中 new_base(int a1,int b1):base(a1,b1){} };
练习:利用初始化参数列表 去初始化基类私有成员 并定义输出接口
C++ struct Node{ int m; }; class base{ private : char str[100]; struct Node node; }
5.基类和派生类的构造函数
C++ #include <iostream> using namespace std; class base{ public: base(){ cout << "调用base基类的无参构造函数" << endl; } base(int n):n(n){ cout << "调用base基类的带参构造函数" << ":" << this->n << endl; } private: int n; }; class new_base:public base{ public: new_base(){ cout << "调用new_base派生类的无参构造函数" << endl; } new_base(int m):base(m){ cout << "调用new_base派生类的带参构造函数" << ":"<< m << endl; } }; int main(int argc, char const *argv[]) { // base a; //定义派生类对象时 先调用基类的构造函数 再调用派生类的构造函数 // new_base b; new_base b(10086); return 0; }
6.基类和派生类的析构函数
C++ #include <iostream> using namespace std; class base{ public: ~base(){ //再释放基类中成员空间 cout << "调用基类base中的析构函数" << endl; } }; class new_base : public base{ public: ~new_base(){ //先释放派生类中成员空间 cout << "调用派生类new_base中的析构函数" << endl; } }; int main(int argc, char const *argv[]) { new_base obj; return 0; }
总结:
构造函数:
执行顺序先调用基类的构造函数,再调用派生类的构造函数
析构函数:
执行顺序先调用派生类的析构函数,再调用基类的析构函数
注意: 想要派生类创建对象成功,一定要能够调用到基类和派生类的构造函数!!!!
目录
一. 拷贝构造函数(重点)
1.系统会自动生成浅拷贝方法:
2.自己重写拷贝构造函数方法
二.类外定义类中成员函数(接口)
三.类的继承
四.继承
1. 语法:
2. 继承访问权限的问题:
3. 继承方式:影响的是类外函数对基类成员的访问权限
4. 给基类成员初始化
5.基类和派生类的构造函数
6.基类和派生类的析构函数