怎么做网站表格,原创文章网站开发教程,南昌网站建设公司信息,网站怎么做下载网页九十四、菱形继承
94.1 概念
菱形继承又称为钻石继承#xff0c;是由公共基类派生出多个中间子类#xff0c;又由中间子类共同派生出汇聚子类#xff0c;汇聚子类会得到多份中间子类从公共基类继承下来的数据成员#xff0c;会造成空间浪费#xff0c;没有必要。
所以存…九十四、菱形继承
94.1 概念
菱形继承又称为钻石继承是由公共基类派生出多个中间子类又由中间子类共同派生出汇聚子类汇聚子类会得到多份中间子类从公共基类继承下来的数据成员会造成空间浪费没有必要。
所以存在一个问题
汇聚子类会得到多份中间子类从公共基类继承下来的数据成员会造成空间浪费没有必要。会多次对公共基类的数据成员初始化或者释放。如何避免
94.2 形式 A --------公共基类/ \
B C -------中间子类\ /D --------汇聚子类上面那个问题的解决方法虚继承
九十五、虚继承
95.1 作用
使汇聚子类仅获得一份经中间子类从公共基类继承下来的数据成员。
95.2 格式
关键字 virtual在中间子类的继承方式前加 virtual
class 类名:virtual 继承方式 类名 //中间子类可多继承
{中间子类自己的内容;
};95.3 注意
虚继承之后只保留一份中间子类从公共基类继承下来的数据成员但是不知道保留哪个中间子类的所以就会自动调用公共基类的无参构造函数如果想使用公共基类的有参构造函数则需要在汇聚子类中调用公共基类的有参构造函数。
九十六、多态
静态多态在编译时加载— 如 函数重载动态多态在运行时加载
96.1 啥是多态
多态 一种形式 拥有 多种状态例如 一个人在不同环境下有着不同的状态也有不同的 属性 和 功能 多态父类的指针或者引用指向或者初始化子类的对象调用子类对父类重写的函数进而使用子类的功能。 96.2 函数重写
要求 两个类之间必须要有继承关系子类和父类有同名同类型的函数父类中的该函数必须是虚函数
96.3 虚函数
关键字 virtual
在函数前加 virtual -----虚函数虚函数满足继承 如果父类中函数是虚函数那么继承到子类中该函数还是虚函数 如果子类继续被继承那么“孙类”中的该函数还虚函数…
96.4 赋值兼容规则
父类的指针或者引用可以指向或者初始化子类的对象父类指针指向的仅仅只是子类中继承父类的那段空间
96.5 多态中实现函数重写的原理
类中有虚函数时虚函数都会有一个虚指针虚指针在类的最前面指向了虚函数表虚函数表里记录虚函数虚指针和虚函数表是实现多态的重要机制
96.6 虚析构函数
因为父类指针指向子类对象只作用与子类从父类继承下来的那片特殊空间释放父类指针只会把父类指针作用的那块空间释放子类自己拓展的空间没有得到释放从而造成内存泄漏。
虚析构函数 如果把父类中析构函数设置成虚析构函数那么子类拓展的空间就会被一起释放虚析构函数也满足继承。
示例
#include iostream
using namespace std;class Person
{
private:string name;
public:Person() {}Person(string name):name(name){}virtual ~Person(){} //虚析构函数
};
class Stu:public Person
{
private:int id;
public:Stu() {}Stu(string n, int id):Person(n),id(id){}~Stu(){}
};
int main()
{Person *ptr new Stu(zhangsan, 1001);delete ptr; //如果没有虚析构函数的话只释放父类指针作用的空间子类//拓展的空间并没有得到释放会造成内存泄漏。解决方案虚析构函数return 0;
}96.7 纯虚函数 当父类中的虚函数只用来被子类重写并且没有需要去完成的功能那么一般将该虚函数设置成纯虚函数。 格式 virtual 函数返回值类型 函数名(形参列表) 0 ; //纯虚函数
//纯虚函数 是在父类中声明子类中实现96.8 抽象类 概念 抽象类中至少有一个纯虚函数抽象类不能具体的实例化一个对象一般是用来被继承的。 不能实例化对象只能执行子类对象 如果父类中有纯虚函数表示父类是抽象类 子类继承后如果没有对父类中纯虚函数做重写则子类也是一个抽象类不能实例化一个对象。
例如
#include iostream
using namespace std;class A
{
private:int a;
public:virtual void show() 0;//纯虚函数
};class B :public A
{
private:int b;
public:
};int main()
{//B a; 不能实例化一个对象return 0;
}96.9 C中虚函数与纯虚函数的区别 虚函数和纯虚函数可以定义在同一个类中含有纯虚函数的类被称为抽象类而只含有虚函数的类不能被称为抽象类。 虚函数可以被直接使用也可以被子类重载以后以多态的形式调用而纯虚函数必须在子类中实现该函数才可以使用因为纯虚函数在基类有声明而没有定义。 虚函数和纯虚函数都可以在子类中被重载以多态的形式被调用。 虚函数和纯虚函数通常存在于抽象基类之中被继承的子类重载目的是提供一个统一的接口。 虚函数的定义形式virtual{};纯虚函数的定义形式virtual { } 0;在虚函数和纯虚函数的定义中不能有static标识符原因很简单被static修饰的函数在编译时要求前期绑定,然而虚函数却是动态绑定而且被两者修饰的函数生命周期也不一样。
九十七、模板
模板就是建立一个通用的模具大大提高代码的复用性。C除面向对象编程思想外还有另一种编程思想泛型编程主要利用的技术是 模板C提供了两种重要的模板机制函数模板 和 类模板
生活中的模板
97.1 模板的特点
模板是通用的不是万能的模板只是一个框架
97.2 函数模板
97.2.1 作用
函数模板就是建立一个通用的函数其返回值类型或者参数类型不具体制定用一个虚拟的类型来代替。
97.2.2 格式
templatetypename T
函数的定义如
template typename T
T fun(T x, T y) //建立了一个通用的函数实现数据类型之和
{return xy;
}template ------- 创建模板 typename ------- 表明其后是一种数据类型typename还可以用class代替 T ----- 表示数据类型也可以用其他代替
调用时
cout fun(1,2) endl;
cout fun(1.3,1.4) endl;
cout fun(0, 1) endl;97.3 类模板
97.3.1 作用
建立一个通用的类 类中的 成员变量 的类型 不具体制定用一个虚拟类型来代替
97.3.2 格式
templatetypename T
类的定义template ------- 创建模板 typename ------- 表明其后是一种数据类型typename还可以用class代替 T ----- 表示数据类型也可以用其他代替
九十八、异常 作用 可以优雅的解决异常 实现步骤 用 try包裹可能产生异常的地方在产生异常的条件下用 throw抛出异常在 try后面的 catch语句中接收异常并在 catch后的代码块中处理异常
示例
#include iostream
using namespace std;int fun(int x, int y)
{if(y!0){return x/y;}else{throw -1; //抛出异常}
}
int main()
{try{fun(9,0); //把可能发生异常的地方用try包裹起来cout hello 啊 endl; }catch (int e){if(e -1){cout 分母为0不合法 endl;}}return 0;
}小作业
比喻
动物园的讲解员和动物表演
动物园里有一位讲解员他会为每种动物表演做简单的介绍如狮子、大象、猴子等。提示在这个场景中我们可以将动物比作是不同的类而每种动物表演则是类中的函数。讲解员则是一个基类他可以根据每种动物的特点和表演进行相应的介绍。
具体过程如下定义一个基类 Animal其中有一个虛函数perform)用于在子类中实现不同的表演行为。我写的
#include iostream
using namespace std;// base_class
class Animal
{
private:string name;
public:Animal() {}Animal(string name):name(name) {}Animal(const Animal other):name(other.name){}Animal operator(const Animal other){name other.name;return *this;}virtual ~Animal(){}virtual void perform() 0;string get_name(){return this-name;}
};class Lion:virtual public Animal
{
public:Lion() {}Lion(string name):Animal(name) {}Lion(const Lion other):Animal(other){}Lion operator(const Lion other){Animal::operator(other);return *this;}~Lion(){}void perform() {cout Animal::get_name() : 河东狮吼 endl;}
};class Elephant:virtual public Animal
{
public:Elephant() {}Elephant(string name):Animal(name) {}Elephant(const Elephant other):Animal(other){}Elephant operator(const Elephant other){Animal::operator(other);return *this;}~Elephant(){}void perform() {cout Animal::get_name() : 象群践踏 endl;}
};class Monkey:virtual public Animal
{
public:Monkey() {}Monkey(string name):Animal(name) {}Monkey(const Monkey other):Animal(other){}Monkey operator(const Monkey other){Animal::operator(other);return *this;}~Monkey(){}void perform() {cout Animal::get_name() : 专业偷桃 endl;}
};int main()
{Animal *p nullptr;Lion l(狮子狗);Elephant e(孟获);Monkey m(孙猴子);p l;p-perform();p e;p-perform();p m;p-perform();return 0;
}