C++多态(上)

简介: C++多态(上)

多态的概念

多态的概念:通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态

举个例子:比如说买票,普通人是全价买,学生是半价,退伍军人是优先。

多态的定义与实现

多态的构成条件与虚函数

多态很重要的前提就是先继承。

并且要去用基类的指针或者是引用去调用虚函数

被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写

#include<iostream>
using namespace std;
class Person {
public:
  virtual void BuyTicket() { cout << "买票-全价" << endl; }//成员函数前面加一个virtual就成为虚函数
};
class Student:public Person
{
public:
  //这里是虚函数的 重写/覆盖
  virtual void BuyTicket() { cout << "买票-半价" << endl; }//条件是三同:返回值和函数名还有参数相同
};
int main()
{
  Person s1;
  Student s2;
  Person* p = &s1;
  p->BuyTicket();
  p = &s2;
  p->BuyTicket();
  return 0;
}

这里也叫做多态调用。

之前的调用都是普通调用,一直都和对象的类型有关。

多态调用是跟指向的对象有关。

如果改成普通调用就是类型是谁就去调用谁的成员函数,多态调用就是指向的对象是谁就去调用谁的虚函数。

虚函数的重写

子类虚函数可以不加virtual

#include<iostream>
using namespace std;
class Person {
public:
  virtual void BuyTicket() { cout << "买票-全价" << endl; }
};
class Student:public Person
{
public:
  //这里是虚函数的 重写/覆盖
  void BuyTicket() { cout << "买票-半价" << endl; }//只要三同,子类不加virtual也是虚函数
}
int main()
{
  Person s1;
  Student s2;
  Person* p = &s1;
  p->BuyTicket();
  p = &s2;
  p->BuyTicket();
  return 0;
}

不过这里建议都加上virtual。

协变

三同中,返回值可以不同,但是要求返回值必须是一个父子类关系的指针或者引用。

#include<iostream>
using namespace std;
class Person {
public:
  virtual Person* BuyTicket() { cout << "买票-全价" << endl; return this; }
};
class Student:public Person
{
public:
  virtual Student* BuyTicket() { cout << "买票-半价" << endl;  return this; }
};
int main()
{
  Person s1;
  Student s2;
  Person* p = &s1;
  p->BuyTicket();
  p = &s2;
  p->BuyTicket();
  return 0;
}

正常运行。

析构函数的重写

#include<iostream>
using namespace std;
class A
{
public:
  ~A()
  {
    cout << "delete s1" << endl;
    delete[] s1;
  }
protected:
  int* s1 = new int[20];
};
class B :public A
{
public:
  ~B()
  {
    cout << "delete s2" << endl;
    delete[] s2;
  }
protected:
  int* s2 = new int[20];
};
int main()
{
  A a;
  B b;
  return 0;
}

目前看来确实没什么问题,都是正常调用,来看看如下的情况:

这里导致了内存泄漏,因为析构函数不是虚函数,只能完成普通调用,所以最好在析构面前加一个virtual。

这下子就可以了。

其实子类不加virtual这里更合适,更方便。

所以在实现父类的时候,最好无脑的给析构函数加virtual。

C++11 override 和 final

final

如何实现一个不被继承的类?

C++11提供了一个关键字,类定义的时候加final:

如果放在父类的某个虚函数后面就是不让这个虚函数被重写。

但是这个情况很少见。

override

检查派生类虚函数是否重写了基类某个虚函数,如果没有重写编译报错。

重载、覆盖(重写)、隐藏(重定义)的对比

抽象类

在虚函数的后面写上 =0 ,则这个函数为纯虚函数。包含纯虚函数的类叫做抽象类(也叫接口类),抽象类不能实例化出对象。派生类继承后也不能实例化出对象,只有重写纯虚函数,派生

类才能实例化出对象。纯虚函数规范了派生类必须重写,另外纯虚函数更体现出了接口继承。

#include <iostream>
using namespace std;
class A//抽象类
{
public:
  virtual void add() = 0 {};//纯虚函数
};
class B:public A
{
public:
  void add(){}
};
int main()
{
  B s;//但是A仍然不能实例化
  return 0;
}

这就是说给某个函数必须进行重写。

抽象类一般用于,比如说车,他是一个概念,但是他有自行车,电动车,跑车等等,然后还被分为好多的品牌,所以车必须要分类出来。

接口继承和实现继承

普通函数的继承是一种实现继承,派生类继承了基类函数,可以使用函数,继承的是函数的实现。虚函数的继承是一种接口继承,派生类继承的是基类虚函数的接口,目的是为了重写,达成多态,继承的是接口。所以如果不实现多态,不要把函数定义成虚函数。

相关文章
|
1月前
|
存储 编译器 数据安全/隐私保护
【C++】多态
多态是面向对象编程中的重要特性,允许通过基类引用调用派生类的具体方法,实现代码的灵活性和扩展性。其核心机制包括虚函数、动态绑定及继承。通过声明虚函数并让派生类重写这些函数,可以在运行时决定具体调用哪个版本的方法。此外,多态还涉及虚函数表(vtable)的使用,其中存储了虚函数的指针,确保调用正确的实现。为了防止资源泄露,基类的析构函数应声明为虚函数。多态的底层实现涉及对象内部的虚函数表指针,指向特定于类的虚函数表,支持动态方法解析。
32 1
|
2月前
|
编译器 C++
C++入门12——详解多态1
C++入门12——详解多态1
47 2
C++入门12——详解多态1
|
7月前
|
C++
C++中的封装、继承与多态:深入理解与应用
C++中的封装、继承与多态:深入理解与应用
171 1
|
2月前
|
C++
C++入门13——详解多态2
C++入门13——详解多态2
88 1
|
4月前
|
存储 编译器 C++
|
5月前
|
存储 编译器 C++
【C++】深度解剖多态(下)
【C++】深度解剖多态(下)
57 1
【C++】深度解剖多态(下)
|
5月前
|
存储 编译器 C++
|
5月前
|
机器学习/深度学习 算法 C++
C++多态崩溃问题之为什么在计算梯度下降时需要除以批次大小(batch size)
C++多态崩溃问题之为什么在计算梯度下降时需要除以批次大小(batch size)
|
5月前
|
Java 编译器 C++
【C++】深度解剖多态(上)
【C++】深度解剖多态(上)
58 2
|
5月前
|
程序员 C++
【C++】揭开C++多态的神秘面纱
【C++】揭开C++多态的神秘面纱