封装、继承和多态是面向对象语言的三大特性,其中多态是最复杂、内容最多的特性,在这篇文章中,我们就来讨论一下多态的实现及原理。
所谓多态,就是同一个操作作用于不同对象时会产生不同的效果。比如说,汪星人会叫,喵星人也会叫,但是它们叫的声音是不同的。再比如我们打lol时,每个英雄都有Q,W,E,R四个技能,但不同的英雄在释放这四个技能时打出的效果是不一样的。多态可以分为静态多态和动态多态,我们先来看看动态多态。
动态多态可以通过虚函数和继承来实现,在C++中,我们可以定义父类的引用或指针,他们同样能够指向子类对象。上述特性确保了动态多态的实现。
#include<iostream>
#include<string>
using namespace std;
class Animal {
private:
string name;
string bark_type; //叫声的类型
public:
Animal() = default;
Animal(string the_name, string the_bark_type) :name(the_name), bark_type(the_bark_type) {}
//virtual string get_bark();
virtual void bark(); //叫声函数
};
/*string Animal:: get_bark() {
return this->bark_type;
}*/
void Animal::bark() {
cout << "I can bark " << this->bark_type<< endl;
}
void my_bark(Animal *ptr) {
ptr->bark();
}
//猫类
class Cat :public Animal {
private:
string name;
string bark_type;
public:
Cat(string the_name, string the_type_bark) :name(the_name), bark_type(the_type_bark) {}
void bark() override;
};
void Cat::bark() {
cout << "I can bark " << this->bark_type << endl;
}
//狗类
class Dog :public Animal {
private:
string name;
string bark_type;
public:
Dog(string the_name, string the_type_bark) :name(the_name), bark_type(the_type_bark) {}
void bark() override;
};
void Dog::bark() {
cout << "I can bark " << this->bark_type << endl;
}
int main() {
Animal* p1 = new Dog("Trump","wang wang");//父类指针可以指向子类对象,引用也有相同的操作
Animal* p2 = new Cat("Baden","miao miao");
my_bark(p1);
my_bark(p2);
delete(p1);
delete(p2);
}
那么多态实现的原理又是什么?当我们创建一个一个类的对象时,同时也创建了一个虚函数表(由编译器实现),这个虚函数表中包括了该对象所属类的所有虚函数指针。那么对象时如何寻找这些虚函数的呢?在我们创建对象时,编译器不但为对象开辟了内存,同时还会增加一个vptr指针,他指向虚函数表的开头。当我们定义了一个指向某个实例的指针,比如指向Dog的p1, 之后我们调用bark函数时,p1所指的实例的vptr会优先从虚函数表中寻找bark虚函数,若存在则执行;若不存在,则像执行类中一般函数那样执行。p2同理。
617

被折叠的 条评论
为什么被折叠?



