您的位置:首页 > 编程语言 > C语言/C++

如何理解C++的多态性和类型动态绑定?

2015-12-03 19:20 363 查看

一.动态类型和动态绑定

第一部分参考:/article/2031612.html

1.对象的静态类型:对象声明时的类型,在编译期确定的

2.对象的动态类型:目前所指对象的类型。是在运行期决定的。对象的动态类型可以更改,但是静态类型无法更改。

示例:

class B
{
}
class C : public B
{
}
class D : public B
{
}
D* pD = new D();//pD的静态类型是它声明的类型D*,动态类型也是D*
B* pB = pD;//pB的静态类型是它声明的类型B*,动态类型是pB所指向的对象pD的类型D*
C* pC = new C();
pB = pC;//pB的动态类型是可以更改的,现在它的动态类型是C*


3.静态绑定:某特性(函数)依赖与对象的静态类型,在编译期确定。

4.动态绑定:某特性(函数)依赖于对象的动态类型,在运行期确定。

一般而言,只有虚函数使动态绑定的,依赖于对象的动态类型,非虚函数是静态绑定的依赖于对象的静态类型。

#include <iostream>
using namespace std;

class B
{
public:
void DoSomething(){
std::cout << "B::DoSomething()" << endl;
}
virtual void vfun(){
std::cout << "B::vfun()" << endl;
}
};

class D : public B
{
public:
void DoSomething(){
std::cout << "D::DoSomething()" << endl;
}
virtual void vfun(){
std::cout << "D::vfun()" << endl;

}
};

int main()
{
D* pd = new D();
B* pb = pd;
pd->DoSomething();     //D::DoSomething()
pb->DoSomething();     //B::DoSomething()

pd->vfun();            //D::DoSomething()
pb->vfun();        //D::DoSomething()
return 0;
}


注意:当虚函数中含有缺省的参数(默认参数时),虚函数时动态绑定的,依赖于对象的动态类型,但是缺省参数是静态的,依赖于对象的静态类型。示例:

#include <iostream>
using namespace std;

class Person
{
public:
virtual void print(){
std::cout << "I'm a person" << endl;
}

};

class Chinese : public Person
{
public:
virtual void print(){
std::cout << "I'm as Chinese" << endl;
}

};

class American : public Person
{
public:
virtual void print(){
std::cout << "I'm as American" << endl;
}

};

//reference
void printPerson(Person& person){
person.print();
}
//pointer
void printPerson(Person* p){
p->print();
}
int main()
{
Person p;
Chinese c;
American a;
printPerson(p);
printPerson(c);
printPerson(a);

printPerson(&p);
printPerson(&c);
printPerson(&a);

return 0;
}


View Code
4.多态的实现:多态是由继承和虚函数实现的,因为虚函数是动态绑定的,依赖于调用对象(静态类型为基类的指针和引用)的动态类型,所以根据动态类型的不同,而导致操作不同,也就是多态性。

3.虚函数的实现:简单的说虚函数是通过虚函数表来实现的。

每个带有虚函数的类,都会有一个虚函数表(vtbl),表中的每一项记录它一个的虚函数的地址。实际上一个函数指针的数组。类的对象的最前面存储虚函数表的地址。

虚函数表在类的继承中也会继承和重写,当有重写发生时,就会产生多态性。

#include <iostream>
using namespace std;
class Person
{
public:
virtual void print(){
std::cout << "I'm a person" << endl;
}
virtual void foo(){}
};

class Chinese : public Person
{
public:
virtual void print(){
std::cout << "I'm as Chinese" << endl;
}
virtual void foo2(){}
};
class American : public Person
{
public:
virtual void print(){
std::cout << "I'm as American" << endl;
}
};
//reference
void printPerson(Person& person){
person.print();
}
//pointer
void printPerson(Person* p){
p->print();
}
int main()
{
Person p;
Chinese c;
American a;
printPerson(&p);
printPerson(&c);
printPerson(&a);
return 0;
}


Person 类的vtbl : Person::print()的地址,Person::foo()的地址

Chinese类的地址:Chinese::print()的地址,Person::foo()的地址,Person::foo1()的地址

American类的地址:American::print()的地址,Person::foo()的地址

三、总结

  多态是C++的三大特性之一,非常重要,产生的条件是继承关系,基类中存在虚成员函数,派生类override(重写覆盖)基类的的虚成员函数,在代码上表现为基类对象的指针或引用调用虚成员函数,运行结果表现为实际调用各自派生类重写的函数。

多态的核心虚成员函数是动态绑定的,即依赖于对象的动态类型。理解多态的难点是虚函数的实现机制,即虚函数表。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: