韩国做 mp4下载网站,全面的锦州网站建设,河北网站开发联系电话,租用网站如何制作网页前言 大家好吖#xff0c;欢迎来到 YY 滴C系列 #xff0c;热烈欢迎#xff01; 本章主要内容面向接触过C的老铁 主要内容含#xff1a; 欢迎订阅 YY滴C专栏#xff01;更多干货持续更新#xff01;以下是传送门#xff01; 目录 一.多态的概念二.多态的实现1#xff… 前言 大家好吖欢迎来到 YY 滴C系列 热烈欢迎 本章主要内容面向接触过C的老铁 主要内容含 欢迎订阅 YY滴C专栏更多干货持续更新以下是传送门 目录 一.多态的概念二.多态的实现1虚函数虚函数表2虚函数的重写覆盖3多态的构成条件4虚函数重写的两种特殊情况【1】协变(基类与派生类虚函数返回值类型不同)【2】析构函数的重写(基类与派生类析构函数的名字不同 三.【override】【final】关键字——帮助用户检测是否重写(C11)【1】 final表示虚函数不能被重写被重写即报错【2】override检查虚函数是否重写了别的虚函数重写了即报错 四. 多态的具体应用抽象类接口类)(纯虚函数类1利用 [ 只有重写纯虚函数 派生类才能实例化出对象 ] 性质2实现继承与接口继承 一.多态的概念 多态是在不同继承关系的类对象去调用 同一 函数产生了 不同 的行为。比如Student继承了Person。Person对象买票全价Student对象买票半价。例iphone和安卓手机用户打车同程不同价 二.多态的实现
1虚函数虚函数表 虚函数即被 virtual 修饰的类成员函数称为虚函数。 class Person {
public:virtual void BuyTicket() { cout 买票-全价 endl;}
};虚函数表本质是一个存虚函数指针 的 指针数组一般情况这个数组最后面放了一个nullptr。虚函数表虚函数表存的是虚函数指针不是虚函数虚函数和普通函数一样的都是存在代码段的只是他的指针又存到了虚函数表中。一个含有虚函数的类中都至少都有一个虚函数表指针因为虚函数的地址要被放到虚函数表中虚函数表也简称虚表 2虚函数的重写覆盖 虚函数的重写(覆盖) 派生类中有一个跟基类完全相同的虚函数 (即派生类虚函数与基类虚函数的返回值类型、函数名字、参数列表完全相同) 称子类的虚函数 重写 了基类的虚函数。 3多态的构成条件 必须通过 基类的指针 来 引用 调用虚函数被调用的函数 必须是虚函数且 派生类必须对基类的虚函数进行重写 //多态条件2被调用的函数 必须是虚函数
class Person {
public:virtual void BuyTicket() { cout 买票-全价 endl; }
};
class Student : public Person {
public: //多态条件2派生类必须对基类的虚函数进行重写virtual void BuyTicket() { cout 买票-半价 endl; }
/*注意在重写基类虚函数时派生类的虚函数在不加virtual关键字时虽然也可以构成重写(因
为继承后基类的虚函数被继承下来了在派生类依旧保持虚函数属性),但是该种写法不是很规范不建议
这样使用*/
/*void BuyTicket() { cout 买票-半价 endl; }*/
};void Func(Person p) //多态条件1必须通过基类的指针来“引用”调用虚函数
{
p.BuyTicket();
}int main()
{
Person ps;
Student st;
Func(ps);
Func(st);return 0;
}4虚函数重写的两种特殊情况
【1】协变(基类与派生类虚函数返回值类型不同) 派生类重写基类虚函数时 与基类虚函数 返回值类型不同 。即如下代码所示【基类虚函数返回基类对象的指针或者引用派生类虚函数返回派生类对象的指针或者引用时】称为协变 class A{};
class B : public A {};
class Person {
public:virtual A* f() {return new A;}
};
class Student : public Person {
public:virtual B* f() {return new B;}
};【2】析构函数的重写(基类与派生类析构函数的名字不同 如果 基类的析构函数为虚函数 此时派生类析构函数只要定义 无论是否加virtual关键字 都与基类的析构函数构成重写虽然基类与派生类析构函数名字不同。 虽然函数名不相同【~Person() 】 【~Student() 】看起来违背了重写的规则其实不然这里可以理解为编译器对析构函数的名称做了特殊处理编译后析构函数的名称统一处理成 destructor 。 class Person {
public: //基类的析构函数为虚函数virtual ~Person() {cout ~Person() endl;}
};class Student : public Person {
public://~Student() { cout ~Student() endl; 不加virtual也行virtual ~Student() { cout ~Student() endl; }
};
// 只有派生类Student的析构函数重写了Person的析构函数下面的delete对象调用析构函数
//才能构成多态才能保证p1和p2指向的对象正确的调用析构函数。
int main()
{Person* p1 new Person;Person* p2 new Student;delete p1;delete p2;return 0;
}三.【override】【final】关键字——帮助用户检测是否重写(C11) 从上面可以看出C对函数重写的要求比较严格但是有些情况下由于疏忽可能会导致函数 名字母次序写反而无法构成重载而这种错误在编译期间是不会报出的只有在程序运行时没有 得到预期结果才来debug会得不偿失因此C11从两个角度提供了 override 和 final 两个关键字可以帮 助用户检测是否重写。 final表示虚函数不能被重写被重写即报错 override检查虚函数是否重写了别的虚函数重写了即报错 【1】 final表示虚函数不能被重写被重写即报错
class Car
{
public:virtual void Drive() final {}
};
class Benz :public Car
{
public:virtual void Drive() {cout Benz-舒适 endl;}
};【2】override检查虚函数是否重写了别的虚函数重写了即报错
class Car{
public:virtual void Drive(){}
};
class Benz :public Car {
public:virtual void Drive() override {cout Benz-舒适 endl;}
};四. 多态的具体应用抽象类接口类)(纯虚函数类
1利用 [ 只有重写纯虚函数 派生类才能实例化出对象 ] 性质 在虚函数的后面写上 0 则这个函数为 纯虚函数 。 包含纯虚函数的类 叫做 抽象类也叫接口类 [ 抽象类不能实例化出对象 ][ 派生类继承后也不能实例化出对象 ] 。只有 [ 重写纯虚函数 ] 派生类才能实例化出对象。纯虚函数规范了派生类必须重写另外纯虚函数更体现出了接口继承。 class Car
{
public:
virtual void Drive() 0; //在虚函数的后面写上 0,这个函数为 纯虚函数
};class Benz :public Car
{
public:virtual void Drive(){cout Benz-舒适 endl; //只有 [ 重写纯虚函数 ] 派生类才能实例化出对象}
};class BMW :public Car
{
public:virtual void Drive(){cout BMW-操控 endl;}
};void Test()
{
Car* pBenz new Benz;pBenz-Drive();Car* pBMW new BMW;pBMW-Drive();
}2实现继承与接口继承 普通函数的继承是一种 实现继承 派生类继承了基类函数可以使用函数继承的是函数的实现。虚函数的继承是一种 接口继承 派生类继承的是基类虚函数的接口 目的是为了重写达成多态 继承的是接口。所以如果不实现多态不要把函数定义成虚函数。