多态(C++)上

简介: 多态(C++)

多态的概念


概念


多态即多种形态,当不同对象去执行同一个行为时,会产生不同的状态


多态的定义及实现


多态的构成条件


必须通过基类的指针/引用去调用虚函数( virtual所修饰)

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


69d4dd2f4d570423172cb47f4ef657a9_f389d34ba03b4459ae57af0e14a49f27.png


class Person
{
public:
  virtual void Buyticket()
  {
  cout << "Person:买票-全价" << endl;
  }
};
class Student:public Person
{
public:
  virtual void Buyticket()
  {
  cout << "Student:买票-半价" << endl;
  }
};
//多态调用
void Display(Person& p)
{
  p.Buyticket();
}
int main()
{
  Person pn;
  Display(pn);
  Student st;
  Display(st);
  return 0;
}

655a0c2ebf11c881d4b55deefc03da1e_4f5da8fc586a4567912f7e99e2bd8827.png


普通调用:和调用对象的类型有关

多态调用:和指针/引用指向的对象有关


class Person
{
public:
  virtual void Buyticket()
  {
  cout << "Person:买票-全价" << endl;
  }
};
class Student:public Person
{
public:
  virtual void Buyticket()
  {
  cout << "Student:买票-半价" << endl;
  }
};
//普通调用
void Display(Person p)
{
  p.Buyticket();
}
int main()
{
  Person pn;
  Display(pn);
  Student st;
  Display(st);
  return 0;
}

540d4cede7588cfc7b5a99123c0f2e0e_c1d2c9b44355405abb11efb30120111f.png


虚函数


虚函数:被 virtual修饰的类成员函数称作虚函数


class Person
{
public:
  virtual void Buyticket()
  {
  cout << "Person:买票-全价" << endl;
  }
};


虚函数的重写


虚函数的重写:派生类中有一个和基类完全相同的虚函数,称派生类的虚函数重写了基类的虚函数


虚函数重写的两个例外


协变(基类与派生类虚函数返回值类型不同)

派生类重写基类虚函数时,与基类虚函数返回值类型不同。也就是基类虚函数返回基类对象的指针/引用,派生类虚函数返回派生类对象的指针/引用

class Person
{
public:
  ~Person()
  {
  cout << "~Person()" << endl;
  delete[] _p;
  }
protected:
  int* _p = new int[10];
};
class Student :public Person
{
public:
  ~Student()
  {
  cout << "~Student()" << endl;
  delete[] _s;
  }
protected:
  int* _s = new int[10];
};
int main()
{
  Person pn;
  Student st;
  return 0;
}


69cc2b74e5298b0ae8097ecb77e7092f_207a0326b59d406b83d96484a6196de9.png


析构函数的重写(基类与派生类析构函数名不同)

先观察如果析构函数不设置为虚函数

class Person
{
public:
  ~Person()
  {
  cout << "~Person()" <<endl;
  delete[] _p;
  }
protected:
  int* _p = new int[10];
};
class Student :public Person
{
public:
  ~Student()
  {
  cout << "~Student()" << endl;
  delete[] _s;
  }
protected:
  int* _s = new int[20];
};
int main()
{
  Person pn;
  Student st;
  return 0;
}


afa908ac402c21efe7970150d9f66b4c_dd55eb2e45af44d384913c0aed3234a3.png


运行起来似乎没有什么问题,做如下修改,结果又是如何


int main()
{
  Person* ptr1 = new Person;
  Person* ptr2 = new Student;
  delete ptr1;
  delete ptr2;
  return 0;
}

7eae2358a57975d2df9ef80c490b560f_054002b33ce847349a304dc68e641ff7.png


由运行结果可知,发生了内存泄漏,Student的资源并没有释放;delete的行为是:使用指针调用析构函数,由于是普通调用,函数与调用对象的类型有关,所以造成了内存泄漏;如果将函数设置为虚函数结构会怎么样呢?


class Person
{
public:
  virtual ~Person()
  {
  cout << "~Person()" << endl;
  delete[] _p;
  }
protected:
  int* _p = new int[10];
};
class Student :public Person
{
public:
  virtual ~Student()
  {
  cout << "~Student()" << endl;
  delete[] _s;
  }
protected:
  int* _s = new int[20];
};


5b7fbcdf4c3fe3d98b5eb4a56ee34bf5_142795c63e79427d806dca801e5fb3e2.png


内存泄漏的问题完美地解决


虽然函数名不同,这里其实是构成了虚函数的重写,编译器对析构函数的名称做了处理,编译后的析构函数的名称统一处理成 destructor


子类虚函数可以不加 virtual修饰(不推荐)


C++11override和final


final:修饰虚函数,表示该虚函数不能被重写

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


重载,覆盖,隐藏的对比



抽象类


概念


在虚函数的后面加上=0,称这个函数为纯虚函数,包含纯虚函数的类称作抽象类,抽象类不能实例化对象;派生类继承后也不能实例化对象,只有重写纯虚函数,派生类才能实例化对象;纯虚函数规定了派生类必须重写


class Car
{
public:
  virtual void Drive()=0;
};
int main()
{
  Car c;
  return 0;
}


f8643f31be7e0d357a59b72bd2c727c0_bf2fab4037194373962ff2dd21aa8b5f.png


纯虚函数不可以实例化


class Car
{
public:
  virtual void Drive() = 0;
};
class NIO : public Car
{
public:
  virtual void Drive()
  {
  cout << "安全驾驶" << endl;
  }
};
int main()
{
  NIO et7;
  et7.Drive();
  return 0;
}

6fb5000c6a0941432ab2d65b332f9bc2_b0d9e64ac3de43bf90e322446fc9a134.png


接口继承和实现继承


普通函数的继承是是实现继承,派生类继承了基类函数,可以使用函数,继承的是函数的实现;虚函数的继承是一种接口继承,派生类继承的是基类虚函数的接口,目的是为了重写,构造多态,继承的是接口


目录
相关文章
|
4月前
|
存储 编译器 C++
|
2月前
|
编译器 C++
多态的讲解
多态的讲解
25 2
|
2月前
深入理解多态
深入理解多态
10 0
|
10月前
|
C++
多态(C++)下
多态(C++)
52 0
|
10月前
什么是多态?
什么是多态?
40 0
|
10月前
什么是多态。
什么是多态。
61 0
|
5月前
|
编译器 C++
【C++】:多态
【C++】:多态
42 0
|
7月前
|
编译器 C++
|
7月前
|
大数据 编译器 C++