当前位置: 首页> 教育> 大学 > 5118站长工具箱_西安旅游攻略景点必去_百度网络营销中心客服电话_合肥关键词排名工具

5118站长工具箱_西安旅游攻略景点必去_百度网络营销中心客服电话_合肥关键词排名工具

时间:2025/7/10 8:52:13来源:https://blog.csdn.net/2201_75956982/article/details/143978352 浏览次数:0次
5118站长工具箱_西安旅游攻略景点必去_百度网络营销中心客服电话_合肥关键词排名工具

目录

一、多态的概念

二、多态的定义及实现

1、多态的构成条件

2、虚函数

3、虚函数的重写

3.1、协变:

3.2、析构函数重写:

4、override 和 final 关键字

5、重载、覆盖、隐藏

三、抽象类

1、接口继承

2、实现继承


 

一、多态的概念

顾名思义,多态就是多种形态,举个例子:比如说买票这个行为,当普通人买票时是全价票,学生买票时是半价票,军人买票时是优先买票。也就是说一件事,每个不同的类去做,会发生不一样的行为称之为多态。

二、多态的定义及实现

1、多态的构成条件

1、多态是在不同继承关系的类对象,去调用同一函数,产生了不同的行为。比如 Student 继承了Person。 Person 对象买票全价, Student 对象买票半价。
2、必须通过基类的指针或者引用调用虚函数。
3、被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写。

2、虚函数

虚函数就是被virtual修饰的类成员函数成为虚函数。

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

3、虚函数的重写

当派生类中和基类有一个完全相同的虚函数。派生类和基类都得写才标准。
class Person {
public:virtual void BuyTicket(){cout << "买票-全价" << endl;}
};class Student : public Person {
public:virtual void BuyTicket(){cout << "买票-半价" << endl;}//void BuyTicket() { cout << "买票-半价" << endl}
};void Func(Person& p)
{p.BuyTicket();
}int main()
{Person ps;Func(ps);Student st;  Func(st);return 0;
}

3.1、协变:

派生类重写基类虚函数时,与基类虚函数返回的类型不同。

3.2、析构函数重写:

如果基类的析构函数是虚函数,那么派生类的析构函数默认会和基类的析构函数构成重写,虽然函数名不同,但是编译器进行编译后,把析构函数统一处理为destructor。

class Person
{
public:virtual void BuyTicket(){cout << "全价" << endl;}virtual Person* F(){return new Person;}virtual ~Person(){cout << "~Person" << endl;}
};
class Student : public Person
{
public:virtual void BuyTicket(){cout << "半价" << endl;}virtual Student* F(){return new Student;}virtual ~Student(){cout << "~Student" << endl;}
};
void Test(Person& p)
{p.BuyTicket();
}
int main()
{Person p;Student s;Test(p);Test(s);return 0;
}析构了两次~Person

 

class Person {
public:~Person(){cout << "~Person()" << endl;}
};class Student : public Person {
public:~Student(){cout << "~Student()" << endl;}
};int main()
{Person* p1 = new Person;Person* p2 = new Student;delete p1;delete p2;return 0;
}

为什么会调用两次~Person()? 而且没有调用~Student()。子类的指针赋给父类指针时,会发生切割。p2 指针只会指向属于父类的那一部分,子类的析构函数自然也就没有赋值过去。所以调用的是父类的析构函数, 并不能正确的释放掉动态开辟的空间。只有派生类 Student 的析构函数重写了 Person 的析构函数,下面的 delete 对象调用析构函数,才能构成多态,才能保证 p1 和 p2 指向的对象正确的调用析构函数。
修改后:
class Person {
public:virtual ~Person(){cout << "~Person()" << endl;}
};class Student : public Person {
public:virtual ~Student(){cout << "~Student()" << endl;}
};int main()
{Person* p1 = new Person;Person* p2 = new Student;delete p1;delete p2;return 0;
}

4、override 和 final 关键字

C++11中, 用来辅助进行虚函数多态的多种复杂情况,避免出现疏忽而导致错误的情况出现。

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

class Person
{
public:/*virtual*/ void BuyTicket(){cout << "全价票" << endl;}
};
class Student : public Person
{
public:virtual void BuyTicket() override//报错{cout << "半价票" << endl;}
};
class Child : public Student
{
public:virtual void BuyTicket() override{cout << "半价票" << endl;}
};

final : 修饰虚函数,表示这个虚函数不能被重写。

class Person
{
public:virtual void BuyTicket(){cout << "全价票" << endl;}
};
class Student : public Person
{
public:virtual void BuyTicket() final{cout << "半价票" << endl;}
};
class Child : public Student
{
public:virtual void BuyTicket()//{cout << "半价票" << endl;}
};

5、重载、覆盖、隐藏

1.重载指的是,函数名在一个作用域,并且函数名相同,参数不同的情况,那么这两个函数就构成了函数重载,编译器在进行处理的时候会根据参数形成不同的函数表。

2.重写指的是,两个函数在基类和派生类的作用域下,前提是函数名、参数、返回值都一样的情况下,如果是虚函数,那么就构成了重写,其中子类可以不写virtual,可以理解为虚函数的属性被从基类中继承了下来,但是并不推荐这样写,其中要注意特殊情况,比如协变和析构函数的情况。

3.隐藏指的是,两个函数在基类和派生类的作用域下,当函数名相同的时候,如果不符合重写的定义那么就是重定义了,比如在继承中见到的很多种情况。

三、抽象类

抽象类的定义:在虚函数后面写上=0,就是纯虚函数,有纯虚函数的类就是抽象类,特点是不能实例化出一个具体的对象派生类也是不能,只有在重写了虚函数,才能实例化,纯虚函数体现了派生类要重写的这个原则,同时也体现了接口继承的概念。

基类 - 抽象类 - 不能实例化出对象
class Car
{
public:virtual void Drive() = 0; 纯虚函数,不需要实现它
};派生类
class Benz :public Car
{
public:virtual void Drive() 必须重写基类虚函数,派生类才能实例化出对象{cout << "Benz-舒适" << endl;}
};class BMW :public Car
{
public:virtual void Drive(){cout << "BMW-操控" << endl;}
};int main()
{基类是抽象类,不能实例化出对象,但可以定义基类指针,用来实现多态Car* pBenz = new Benz;pBenz->Drive();Car* pBMW = new BMW;pBMW->Drive();return 0;
}

1、接口继承

接口继承(Interface Inheritance)是指从一个纯虚基类(pure virtual base class)继承而来,目的是为了实现一个类的接口,使得派生类必须实现该接口中定义的所有纯虚函数。接口继承的主要目的是实现类的接口复用,它并不关心实现细节。在接口继承中,派生类只需要实现基类中定义的纯虚函数,不需要关心基类中其他的数据和函数。

class Shape
{
public:virtual void draw() = 0;//纯虚函数
};
class Cirrle : public Shape
{
public:void draw() override{//实现圆形的绘画}
};
class Squre : public Shape
{void draw() override{//实现矩形的绘画}
};

2、实现继承

实现继承(Implementation Inheritance)是指从一个普通的基类(非纯虚基类)继承而来,目的是为了实现基类中已有的函数或数据。实现继承的主要目的是实现代码复用,它关心基类中的实现细节。在实现继承中,派生类会继承基类中所有的成员函数和数据成员,并且可以重写这些函数以改变它们的行为。

class Person
{
public:virtual void Say(){cout << "Person" << endl;}
};
class Student : public Person
{
public:virtual void Say() override{cout << "Student" << endl;}
};int main()
{Person p;Student s;s.Say();return 0;
}

下章节介绍多态的原理!如有不正之处,希望大家私信我去改正! 

关键字:5118站长工具箱_西安旅游攻略景点必去_百度网络营销中心客服电话_合肥关键词排名工具

版权声明:

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

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

责任编辑: