你的c++学习路上明灯
继承:
一,基本介绍:
1,好处:
减少重复代码。
2,语法:
class 子类(派生类) : 继承方式 父类(基类)
3,
派生类中的成员包含两大部分:
一部分是从基类中继承来的东西,另一部分是自己增加的部分
从基类继承过来的表现其共性,而新增成员体现其个性
二,详细的使用
1.继承方式:
1)公共继承:父类权限不变;
2)保护继承:全部变成保护权限
3)私有继承:全部变为私有权限
上述三种继承方式都无法访问到分类的私有权限下的内容,但是可以访问到保护权限下的。
#define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> using namespace std; //普通实现页面 //需要大量的重复代码,冗余。 //class Java { //public: // // void header() { // cout << "首页,公开课。。。。(公共头部)" << endl; // } // void footer() { // cout << "帮助中心,交流合作。。。(公共底部)" << endl; // } // void content() { // cout << "Java学科视频" << endl; // } // //}; // //class Python { //public: // // void header() { // cout << "首页,公开课。。。。(公共头部)" << endl; // } // void footer() { // cout << "帮助中心,交流合作。。。(公共底部)" << endl; // } // void content() { // cout << "Python学科视频" << endl; // } // //}; //class Cpp { //public: // // void header() { // cout << "首页,公开课。。。。(公共头部)" << endl; // } // void footer() { // cout << "帮助中心,交流合作。。。(公共底部)" << endl; // } // void content() { // cout << "Cpp学科视频" << endl; // } // //}; //继承页面 // 重复的部分只用写一次。 //公共页面类 class basepage { public: void header() { cout << "首页,公开课。。。。(公共头部)" << endl; } void footer() { cout << "帮助中心,交流合作。。。(公共底部)" << endl; } }; class Java : public basepage { public: void content() { cout << "Java学科视频" << endl; } }; class Python : public basepage { public: void content() { cout << "Python学科视频" << endl; } }; class Cpp :public basepage { public: void content() { cout << "Cpp学科视频" << endl; } }; void test1() { cout << "Java下载视频如下:" << endl; Java ja; ja.content(); ja.footer(); ja.header(); cout << "------------------" << endl; cout << "Python下载视频如下:" << endl; Python py; py.content(); py.footer(); py.header(); cout << "------------------" << endl; cout << "Cpp下载视频如下:" << endl; Cpp cp; cp.content(); cp.footer(); cp.header(); cout << "------------------" << endl; } int main() { test1(); return 0; }
2.注意我上面的那句话,无法访问到,这就说明了,父类中私有成员也会被子类继承,只是由编译器隐藏后访问不到了。
#define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> using namespace std; class base { public: int m_A; private: int m_B; protected: int m_C; }; class son1 :public base { public: int m_D; }; //父类所有的非静态成员属性都会被子类继承下去 //父类中的私有成员属性是被编译器给隐藏了。因此访问不到,但是确实是被继承下来了 void test1() { cout << "son1 的大小为:" << sizeof(son1) << endl; //所以此处的大小是16; } int main(){ test1(); return 0; }
3.继承中构造函数和析构函数的调用顺序
创建子类对象后,先构造父类,再构造子类,析构顺序相反。
4.同名成员处理
1)子类对象可以直接访问到子类中的同名成员,
2)子类对象加作用域可以访问到父类同名成员
3)当子类与父类拥有同名的成员函数,子类会隐藏父类中的同名函数,一定要加作用域才能够访问
#define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> using namespace std; class base { public: int m_A=200; void func() { cout << "base-func()函数的调用" << endl; } void func(int a) { cout << "base-func(int a)函数的调用" << endl; } }; class son1 :public base { public: int m_A=100; void func() { cout << "son-func()函数的调用" << endl; } }; //同名成员函数处理 void test1() { son1 s; //子类对象可以直接访问到子类中的同名成员 s.func(); //子类对象加作用域可以访问到父类的同名成员 s.base::func(); //当子类对象与父类对象拥有同名的成员函数,子类会隐藏父类中的同名函数,一定要加作用域才能够访问到哦 } //同名成员属性处理 void test2() { son1 s; cout << s.m_A << endl; cout << s.base::m_A << endl; } int main() { test1(); test2(); return 0; }
5.同名静态成员处理方式和非静态处理方式一样,只不过有两种访问方式(通过对象,通过类名)
#define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> using namespace std; class Base { public: static int m_A; static void func() { cout << "Base-func()的调用" << endl; } static void func(int a) { cout << "Base-func(int a)的调用" << endl; } }; int Base::m_A = 100; class Son:public Base { public: static int m_A; static void func() { cout << "Son-func()的调用" << endl; } }; int Son::m_A = 200; void test1() { //1.通过对象访问 Son s; cout << "通过对象访问" << endl; cout << s.m_A << endl; cout << s.Base::m_A << endl; //2,通过类名访问 cout << "通过类名访问" << endl; cout << Son::m_A << endl; //第一个 ::代表通过类名访问,第二个 ::代表作用域 cout << Son::Base::m_A << endl; } int main() { test1(); return 0; } //同名静态成员处理方式和非静态成员处理方式一样,只不过是有了两种访问方式 //通过类名和通过对象
6.多继承语法
1)c++允许一个类继承多个类(一个子类继承多个父类)
2)多继承可能会引发父类中有同名成员出现,需要加一个作用域区分
3)c++实际开发不建议用多继承(容易引发一些不必要的冲突)
#define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> using namespace std; class Base1 { public: int m_A; Base1() { m_A = 100; } }; class Base2 { public: int m_A; Base2() { m_A = 200; } }; class Son :public Base1, public Base2 { public: int m_C; Son() { m_C = 300; } }; void test1() { Son s; //大小依然是所有的数据大小之和 cout << sizeof(s) << endl; //多继承中如果父类中出现了同名情况,子类使用的时候要加作用域 cout << s.Base1::m_A << endl; cout << s.Base2::m_A << endl; } int main() { test1(); return 0; }
7.菱形继承
菱形继承带来的问题:
子类继承两份相同的数据,导致资源浪费和二义性。
可以用虚继承的方法来解决
所谓虚继承每一个派生类会给自己的子类继承虚基类指针(vbptr)和一份虚基类表,表中记录了虚基类与本类与本类的偏移量。
#define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> using namespace std; class Animal { public: int m_Age; }; //虚继承就是再继承方式的前面加上virtual关键字 //虚继承就是菱形继承问题的解决方法 class sheep:virtual public Animal{}; class tuo :virtual public Animal{}; class sheeptuo : public sheep, public tuo{}; void test1() { sheeptuo st; //两个派生类都从基类中继承了相同的数据,浪费空间,只需要留一份就好了 //应用虚继承以后,两个派生类的子类只从其中继承了一份数据,且数据值以最后一次修改为准 st.sheep::m_Age = 100; st.tuo::m_Age = 200; cout << st.sheep::m_Age << endl; cout << st.tuo::m_Age << endl; } int main() { test1(); return 0; }
多态:
一,基本介绍
多态分为两类:
1)静态多态:函数重载和运算符重载,复用函数名
2)动态多态:派生类和虚函数实现运行时多态。
区别:静态多态的函数地址早绑定---编译阶段确定函数地址
动态多态的函数地址晚绑定---运行阶段确定函数地址
***c++中允许父子类之间的类型转换
#define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> using namespace std; class Animal { public: //函数前面加上virtual关键字,变成虚函数,那么编译器在编译时就不能确定函数调用了 //即:函数地址的先后绑定 virtual void Speak() { cout << "动物在说话" << endl; } }; class Cat :public Animal { public: //重写:函数返回值类型 函数名 参数列表 完全一致 //所以这里的virtual可写可不写 virtual void Speak() { cout << "小猫在说话" << endl; } }; class Dog :public Animal { public: void Speak() { cout << "小狗在说话" << endl; } }; //回调函数,提供多个选择 //c++中允许父子类之间的类型转化 void dospeak(Animal &animal) { animal.Speak(); } void test1() { Cat cat; dospeak(cat); Dog dog; dospeak(dog); } int main() { test1(); return 0; }
二,详细的使用
1.动态多态满足条件:
1)有继承关系
2)子类重写父类的虚函数
2.使用动态多态:
父类的指针或引用指向子类对象
3.重写:函数返回值类型 函数名,参数列表完全一致称为重写。
4.多态的优点
1)代码组织结构清晰
2)可读性强
3)利于前期和后期的扩展以及维护
5.纯虚函数
virtual 返回值类型 函数名 (参数列表)=0;
6.抽象类特点:
1)无法实例化对象
2)子类必须重写抽象类中的纯虚函数,否则也属于抽象类。
#define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> using namespace std; class Base { public: //纯虚函数 //父类的虚函数是用不上的,写了也是白写,所以就出现了纯虚函数的概念 virtual void func() = 0; //一旦有了纯虚函数,该类就称作抽象类 //不能实例化对象 //且子类也必须重写虚函数,不然子类也成了抽象类,也无法实例化对象 }; class Son : public Base { public: void func() { cout << "func()函数的调用" << endl; } }; void test1() { //多态的意义就是 //定义一个父类的指针,指向它的任意一个我们想要使用的子类对象, //从而能使我们调用到该子类对象的函数实现 Base* b = new Son; b->func(); delete b; } int main() { test1(); return 0; }
7.虚析构和纯虚析构的共性
1)可以解决父类指针释放子类对象时不干净
2)都需要有具体的函数实现
区别:如果是纯虚析构,该类属于抽象类,无法实例化对象。
#define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> using namespace std; #include<string> class Animal { public: virtual void Speak() = 0; Animal() { cout << "Animal构造函数的调用" << endl; } //利用纯析构可以解决父类指针释放子类对象时不干净的问题 /*virtual ~Animal() { cout << "Animal析构函数的调用" << endl; }*/ //如果不想让该类实例化对象,就写成纯虚析构 virtual ~Animal() = 0; }; Animal::~Animal() { cout << "Animal纯虚析构函数的调用" << endl; } class Cat :public Animal { public: virtual void Speak() { cout << "小猫在说话" << endl; } Cat(string name) { cout << "Cat构造函数的调用" << endl; m_Name = new string(name); } ~Cat() { cout << "Cat析构函数的调用" << endl; if (m_Name != NULL) { delete m_Name; m_Name = NULL; } } string* m_Name; }; void test1() { Animal* a = new Cat("Tom"); a->Speak(); //父类指针在析构的时候,并不会调用子类中的析构函数,导致子类如果有堆区属性,会出现内存泄漏 delete a; } int main() { test1(); return 0; }
8.实例
给大家两个实例练练手
1)
#define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> using namespace std; //制作饮品-多态 class MakeDrink { public: //煮水 virtual void Boil() = 0; //冲泡 virtual void Brew() = 0; //倒入杯中 virtual void Pour() = 0; //加入辅料 virtual void Add() = 0; void makedrink() { Boil(); Brew(); Pour(); Add(); } }; //制作咖啡 class Coffee : public MakeDrink { public: //煮水 virtual void Boil() { cout << "煮咖啡水" << endl; } //冲泡 virtual void Brew() { cout << "冲泡咖啡" << endl; } //倒入杯中 virtual void Pour() { cout << "倒入咖啡杯中" << endl; } //加入辅料 virtual void Add() { cout << "加入牛奶和糖" << endl; } }; //制作茶 class Tea : public MakeDrink { public: //煮水 virtual void Boil() { cout << "煮茶水" << endl; } //冲泡 virtual void Brew() { cout << "冲泡茶" << endl; } //倒入杯中 virtual void Pour() { cout << "倒入茶杯中" << endl; } //加入辅料 virtual void Add() { cout << "加入茶叶" << endl; } }; void dodrink(MakeDrink * md) {//MakeDrink * md = 子类对象 md->makedrink(); delete md; } void test1() { //MakeDrink* md = new Coffee; //MakeDrink& md = new Coffee; dodrink(new Coffee); cout << "-----------------" << endl; dodrink(new Tea); } int main() { test1(); return 0; }
2)制作电脑
#define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> using namespace std; //抽象不同的零件类 //抽象CPU类 class CPU { public: virtual void calculate() = 0; }; //抽象显卡类 class xianka{ public: virtual void display() = 0; }; //抽象内存条类 class Memory { public: virtual void storage() = 0; }; //电脑类 class Computer { public: Computer(CPU* cpu,xianka* xk,Memory* mem) { m_mem = mem; m_xk = xk; m_cpu = cpu; } //提供工作的函数 void work() { m_cpu->calculate(); m_xk->display(); m_mem->storage(); } ~Computer() { if (m_cpu != NULL) { delete m_cpu; m_cpu = NULL; } if (m_xk != NULL) { delete m_xk; m_xk = NULL; } if (m_mem != NULL) { delete m_mem; m_mem = NULL; } } private: CPU* m_cpu; xianka* m_xk; Memory* m_mem; }; //具体厂商 //inter厂商 class IntelCPU :public CPU { public: virtual void calculate() { cout << "Inter的CPU" << endl; } }; class Intelxianka :public xianka { public: virtual void display() { cout << "Inter的xianka" << endl; } }; class IntelMemory :public Memory { public: virtual void storage() { cout << "Inter的Memory" << endl; } }; //联想厂商 class Lenovo :public CPU { public: void calculate() { cout << "Lenovo的CPU" << endl; } }; class Lenovoxianka :public xianka { public: void display() { cout << "Lenovo的xianka" << endl; } }; class LenovoMemory :public Memory { public: void storage() { cout << "Lenovo的Memory" << endl; } }; void test1() { //创建第一台电脑 CPU* intelCpu = new IntelCPU; xianka* intelxianka = new Intelxianka; Memory* intelmem = new IntelMemory; Computer computer1(intelCpu, intelxianka, intelmem); computer1.work(); cout << "------------------" << endl; //创建第二台电脑 Computer computer2(new IntelCPU, new Intelxianka, new IntelMemory); computer2.work(); } int main() { test1(); return 0; }
东西很多,希望大家认真学习。