本文主要是介绍多态的概念及实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
目录
前言
2. 多态的定义及实现
2.1多态的构成条件
2.2 虚函数
2.3虚函数的重写
重写、重载、重定义的辨析
虚函数重写的两个例外:
2.4 C++11 override 和 final
1. final:修饰虚函数,表示该虚函数不能再被重写
这样就会报错。
2. override: 检查派生类虚函数是否重写了基类某个虚函数,如果没有重写编译报错。
2.5 重载、覆盖(重写)、隐藏(重定义)的对比
易错
3. 抽象类
3.1 概念
3.2 接口继承和实现继承
前言
继承与多态常常伴随出现,前面已经进行了继承的学习,本文讲借助以下要点,进行多态的学习。
2. 多态的定义及实现
2.1多态的构成条件
多态是在不同继承关系的类对象,去调用同一函数,产生了不同的行为。比如Student继承了Person。Person对象买票全价,Student对象买票半价。
class Person {
public:virtual void BuyTicket() { cout << "买票-全价" << endl; }
};class Student : public Person {
public:virtual void BuyTicket() { cout << "买票-半价" << endl; }};void Func(Person& p)
{ p.BuyTicket();
}int main()
{Person ps;Student st;Func(ps);Func(st);return 0;
}
在上述调用中,采用了基类的引用传参,调用了被重写之后的虚函数。结果如下
采用不同的对象取调用函数之后,产生了不同的结果。
但是当我们采用对象传参调用之后,结果又是一样的,这是为什么呢?
下面就对原理进行详细的解释。
2.2 虚函数
class Person {
public:virtual void BuyTicket() { cout << "买票-全价" << endl;}
};
2.3虚函数的重写
重写、重载、重定义的辨析
重写(覆盖)::继承关系中,父子类两个虚函数三同(函数名相同 参数相同 返回值相同)
重载:在同一作用域,函数名相同,参数不同
重定义(隐藏):父子类的函数中,函数名相同,子类隐藏父类的现象。
虚函数重写的两个例外:
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;}
};
class Person {
public:virtual ~Person() {cout << "~Person()" << endl;}
};
class Student : public Person {
public: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;
}
2.4 C++11 override 和 final
1. final:修饰虚函数,表示该虚函数不能再被重写
final放在虚函数的函数名之后(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;}
};
2.5 重载、覆盖(重写)、隐藏(重定义)的对比
易错
答案是B。
原因:
1.我们用p取调用test()函数是允许调用的,因为存在继承
2.调用的test()函数的this指针是A*类型,因此内部调用的func()函数也是A*类型的调用。
3.func()函数完成了重写,同时调用时采用的是父类的指针,因此符合多态调用的概念(父类类型的指针、引用,去调用重写过的虚函数)
4.因此我们用子类的指针调用func()函数时,实际上实现了多态调用。调用的函数体部分是子类重写过的函数体:“B->”
但是内部打印的val值是基类val的值,即 1
那如果采用这种调用呢?
答案是D
这并不构成多态调用,因为this指针的类型是B*。这只是一个简单的隐藏(重定义)。
3. 抽象类
3.1 概念
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;}
};
void Test()
{
Car* pBenz = new Benz;pBenz->Drive();Car* pBMW = new BMW;pBMW->Drive();
}
也就意味着这个地方的多态调用是在多个子类之间实现的,而不是父-子之间实现的
3.2 接口继承和实现继承
这篇关于多态的概念及实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!