什么是多态?如何去理解多态?多态的好处是什么?静态绑定和动态绑定
多态是指类中具有相似功能的不同函数,使用同一个名称来实现;是对类的行为再抽象;
多态从实现的角度可以分为:
(1)编译时的多态:静态联编(重载、强制、参数),程序编译连接阶段完成。
(2)运行时的多态:动态联编(包含),程序运行阶段完成。
其中静态多态是通过函数重载与模板体现的,动态多态是通过虚函数来体现的
多态的好处
1. 应用程序不必为每一个派生类编写功能调用,只需要对抽象基类进行处理即可。大大提高程序的可复用性。//继承
2. 派生类的功能可以被基类的方法或引用变量所调用,这叫向后兼容,可以提高可扩充性和可维护性。 //多态的真正作用,
静态绑定就是编译时期调用函数,动态绑定就是运行时期函数调用
虚函数与动态联编,什么是RTTI?RTTI是干什么的?
虚函数是动态联编的基础,虚函数是非静态成员函数,虚函数经过派生之后,在类族中可以实现运行过程中的多态。
根据赋值兼容规则,可以使用派生类对象代替基类对象。如果用基类类型的指针指向派生类对象,就可以通过这个指针来访问该对象。问题是派生到的只是从基类继承来的同名成员。
下面代码的本意是想通过基类的指针指向派生类对象,从而去调用派生类的成员函数。但是运行结果与预期的不相符合
class Base
{
public:
Base(int a) :ma(a)
{
cout << "Base()" << endl;
clear();
}
~Base() { cout << "~Base()" << endl; }
void clear() { memset(this, 0, sizeof(*this)); }
void show() { cout << "Base::show()" << endl; }
protected:
int ma;
};
class Derive : public Base
{
public:
Derive(int data) :Base(data), mb(data)
{
cout << "Derive()" << endl;
}
~Derive() { cout << "~Derive()" << endl; }
void show() { cout << "Derive::show()" << endl; }
private:
int mb;
};
int main()
{
//Base *p = new Base(0);
//p->show();
Base *p2;
Derive d(10);
p2 = &d;
p2->show();
return 0;
}
我想通过基类指针去调用派生类对象,却调用了基类的同名函数。
但是如果将基类的同名函数设置为virtual虚函数就可以解决这样的问题
class Base
{
public:
Base(int a) :ma(a)
{
cout << "Base()" << endl;
clear();
}
~Base() { cout << "~Base()" << endl; }
void clear() { memset(this, 0, sizeof(*this)); }
virtual void show() { cout << "Base::show()" << endl; }
protected:
int ma;
};
为什么会这样子? 对象类型为Derive,但通常只有在程序运行时才能确定对象的类型。所以编译器生成的代码将在程序执行时,根据对象类型将show()关联到Derive::show()或Base::show()。总之,编译器对虚方法采用动态联编。
由上述分析我们可以得出:
在基类中将成员函数声明为虚函数可以使得基类指针调用同名覆盖方法。
RTTI就是运行时的类型信息RTTI指针存储在虚函数表vftable当中,指向一段类型字符串
抽象类和纯虚函数
含有纯虚函数的类称为抽象类,一般情况下是一个基类,它不代表任何实体 ,因此不用实例化对象 ,他只是给派生类保留公共的覆盖接口(重写)和公共的属性(复用)。
class Animal // 有纯虚函数的类 =》 抽象类
{
public:
Animal(string name) :_name(name) {}
virtual void bark() = 0;// 纯虚函数
protected:
string _name;
};
class Cat : public Animal
{
public:
Cat(string name) :Animal(name) {}
void bark() { cout << _name << " bark:喵喵!" << endl; }
};
class Dog : public Animal
{
public:
Dog(string name) :Animal(name) {}
void bark() { cout << _name << " bark:旺旺!" << endl; }
};
上述Animal动物类不代表任何实体,只是给了一个公共接口bark()函数,该函数是一个虚函数并且赋值为0,因此这就是一个纯虚函数。这个类就是抽象类。
进行如下测试:
int main()
{
Animal *p1 = new Cat("猫");
Animal *p2 = new Dog("二哈");
int *p11 = (int*)p1;
int *p22 = (int*)p2;
//取两个对象的前四个字节进行交换
int tmp = p11[0];
p11[0] = p22[0];
p22[0] = tmp;
p1->bark();
p2->bark();
cout << typeid(*p1).name() << endl;
return 0;
}
这就和上述所说的vfptr与RTTI相关了