您的位置:首页 > 新闻 > 会展 > 浙江省杭州市软装设计公司_怎么去掉2345网址导航_seo常用工具网站_百度推广收费

浙江省杭州市软装设计公司_怎么去掉2345网址导航_seo常用工具网站_百度推广收费

2025/2/25 1:37:37 来源:https://blog.csdn.net/m0_64538862/article/details/145483570  浏览:    关键词:浙江省杭州市软装设计公司_怎么去掉2345网址导航_seo常用工具网站_百度推广收费
浙江省杭州市软装设计公司_怎么去掉2345网址导航_seo常用工具网站_百度推广收费

目录

1. 多态的定义及实现

1.1继承中的多态

1.2虚函数的特殊情况

2. 抽象类

3.C++11关键词override 和 final

4.重载、覆盖/重写、隐藏/重定义的对比


1. 多态的定义及实现

🍪什么是多态?

  • C++ 中,多态(Polymorphism)是面向对象编程的重要特性之一。
  • C++ 多态允许使用基类指针或引用来调用子类的重写方法,从而使得同一接口可以表现不同的行为。

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

🌰举个例子:

定义一个类Person,类中定义一个方法"吃饭",Chinese和British继承Person,同样是调用人“吃饭”的方法,Chinese用筷子吃饭,British用刀叉吃饭,对于不同的人调用该方法应该有不同的结果。

1.1继承中的多态

🍪在继承体系中构成多态的两个条件

  1. 必须通过基类的指针或者引用调用虚函数
  2. 被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写

🍪虚函数与虚函数的重写:

  • 虚函数:virtual修饰的类成员函数
  • 虚函数的重写/覆盖:派生类中有一个跟基类完全相同的虚函数(返回值类型、函数名、参数列表完全相同),称子类的虚函数重写了基类的虚函数。

以上面的吃饭方式为例:

class Person
{
public:// 虚函数virtual void HaveMeal() { cout << "Person --> 工具吃饭" << endl; }};
class Chinese : public Person
{
public:// 对基类虚函数的重写virtual void HaveMeal() { cout << "Chinese --> 筷子吃饭" << endl; }};
class British : public Person
{
public:virtual void HaveMeal() { cout << "British --> 刀叉吃饭" << endl; }};

🍪总结:

  • 普通调用:跟调用对象的类型有关
  • 多态调用:跟指向的对象有关(基类的指针和引用,实际上指向的是派生类对象中基类的部分,仍属于派生类对象)

1.2虚函数的特殊情况

🍪虚函数的三种特殊情况

🌸子类函数可以不加virtual 继承父类的虚函数进行重写

📖Note:

  • 一般建议父类子类虚函数都显式加virtual
class Person
{
public:// 虚函数virtual void HaveMeal() { cout << "Person --> 工具吃饭" << endl; }};
class Chinese : public Person
{
public:// 基类虚函数的重写:不加virtual修饰void HaveMeal() { cout << "Chinese --> 筷子吃饭" << endl; }};
class British : public Person
{
public:void HaveMeal() { cout << "British --> 刀叉吃饭" << endl; }};

🌸🌸协变:虚函数重写时,返回值可以不同,但是要求返回值必须是一个父子类关系的指针或者引用 

📖Note:

  • 只需要满足父子关系即可:如B类继承自A类,则Person中的虚函数返回A*,Chinese中的虚函数返回B*也是满足条件的
class Person
{
public:// 虚函数virtual Person* HaveMeal() { cout << "Person --> 工具吃饭" << endl; return this; }};
class Chinese : public Person
{
public:// 基类虚函数的重写:不加virtual修饰Chinese* HaveMeal() { cout << "Chinese --> 筷子吃饭" << endl; return this;}};
class British : public Person
{
public:British* HaveMeal() { cout << "British --> 刀叉吃饭" << endl; return this;}};

🌸🌸🌸实现父类的函数,一般给析构函数加上virtual 构成多态调用

下例中:Person中有一个new出来的成员,Student类继承自Person类,也有new出来的一个成员,基类和派生类有各自的析构函数进行delete

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

分析以下代码的问题

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

对于创建的两个指针变量,ptr1指向Person对象,ptr2指向Student对象中Person对象的切片 

当delete这两个指针时:

  • delete ptr1:毫无疑问会调用Person的析构函数,释放ptr1指向的空间
  • delete ptr2:实际上调用的也是Person的析构函数,因为普通函数的调用,只和调用对象的类型有关,这里是Person类型的对象调用析构函数,所以只会释放Student对象中Person对象部分的空间,而Student对象的空间没有被释放,造成了内存泄漏

🍪解决方案:析构函数定义为虚函数,使这里的调用为多态调用

📖Tips:

  • 定义基类时,将基类的析构函数使用virtual修饰,可以避免不必要的内存泄漏,虚函数重写时,派生类中的虚函数修饰词virtual可以省略,所以只需要基类的析构函数使用virtual修饰即可。
  • 基类和派生类的析构函数都会被编译器解析成destructor,所以基类和派生类的析构函数可以构成重写
class Person
{
public:virtual ~Person(){cout << "delete-Person:" << _p << endl;delete[] _p;}
protected:int* _p = new int[10];
};class Student : public Person
{
public:~Student(){cout << "delete-Student:" << _s << endl;delete[] _s;}
protected:int* _s = new int[20];};

2. 抽象类

纯虚函数:在虚函数的后面写上 =0 ,则这个函数为纯虚函数。

抽象类:包含纯虚函数的类叫做抽象类/接口类

🍪抽象类的特点:

  • 抽象类不能实例化出对象。
  • 派生类继承后也不能实例化出对象,只有重写纯虚函数,派生类才能实例化出对象。
class Major
{
public:// 纯虚函数virtual void Print() = 0;
};
class Automation :public Major
{
public:// 重写纯虚函数virtual void Print(){cout << "Automation ---> 自动化专业" << endl;}
};
class English :public Major
{
public:virtual void Print(){cout << "English --> 英语专业" << endl;}
};

🍪接口继承和实现继承

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

3.C++11关键词override 和 final

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

📖Tips:

  • 类定义时加final,表示该类是一个最终类,不能被继承 

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

class Major
{
public:virtual void Print() {};
};
class Automation :public Major
{
public:// 重写纯虚函数virtual void Print() override{cout << "Automation ---> 自动化专业" << endl;}
};
class English :public Major
{
public:virtual void Print() override{cout << "English --> 英语专业" << endl;}
};

4.重载、覆盖/重写、隐藏/重定义的对比

📖Tips:

  • 两个基类和派生类的同名函数不构成重写就是重定义

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com