GEEKBAND C++ 面向对象高级编程(第四周)

C++ 动态绑定和静态绑定


首先明确四个名词定义:

  • 静态类型:对象在声明时的类型,编译期就能确定

  • 动态类型:指针或引用所指的对象的类型

  • 静态绑定:绑定的是静态类型,依赖于对象的静态类型

  • 动态绑定:绑定的是动态类型,依赖于对象的动态类型

类的非虚函数都是静态绑定,虚函数都是动态绑定。

下面代码中,

#include 

using namespace std;

class Fruit
{
public:
    void print(){cout << "Fruit::print()" << endl;}
    virtual void process(){cout << "Fruit::process()" << endl;}
};
class Apple : public Fruit
{
public:
    void print(){cout << "Apple::print()" << endl;}
    virtual void process(){cout << "Apple::process()" << endl;}
};
class Pear : public Fruit
{
public:
    void print(){cout << "Pear::print()" << endl;}
    virtual void process(){cout << "Pear::process()" << endl;}
};

int main() {
    Pear* pc = new Pear();
    Apple* pb = new Apple();
    Fruit* pa = new Fruit();
    pa = pb;

    pa->print();
    pb->print();
    pc->print();

    pa->process();
    pb->process();
    pc->process();

    return 0;
}

  • pa的静态类型是Fruit,动态类型先是pc指向的Pear,后被改成pb指向的Apple
  • pb的静态类型和动态类型都是Apple
  • pb的静态类型和动态类型都是Pear

代码执行的结果为:

Fruit::print()
Apple::print()
Pear::print()
Apple::process()
Apple::process()
Pear::process()

可以看到对于类中非虚函数的调用,是静态类型决定的,在编译器就能确定;而虚函数的调用,是动态类型决定的,在运行期才能确定。在运行期确定函数的调用,就是面向对象中所说的多态。


注意
《Effective C++》中建议

1.绝对不要重新定义继承而来的非虚(non-virtual)函数

2.绝对不要重新定义一个继承而来的virtual函数的缺省参数值,因为缺省参数值都是静态绑定(为了执行效率),而virtual函数却是动态绑定。

#include 

using namespace std;

class Fruit
{
public:
    void print(){cout << "Fruit::print()" << endl;}
    virtual void process(int i = 1){cout << "Fruit::process(), i="<< i << endl;}
};
class Apple : public Fruit
{
public:
    void print(){cout << "Apple::print()" << endl;}
    virtual void process(int i = 10){cout << "Apple::process(), i="<< i << endl;}
};
class Pear : public Fruit
{
public:
    void print(){cout << "Pear::print()" << endl;}
    virtual void process(int i = 20){cout << "Pear::process(), i="<< i << endl;}
};

int main() {
    Pear* pc = new Pear();
    Apple* pb = new Apple();
    Fruit* pa = pc;
    pa = pb;

    pa->print();
    pb->print();
    pc->print();

    pa->process();
    pb->process();
    pc->process();

    return 0;
}
Fruit::print()
Apple::print()
Pear::print()
Apple::process(), i=1
Apple::process(), i=10
Pear::process(), i=20

上面的代码,pa的process函数调用的是子类的process,但是参数的默认值却是父类的默认值。

你可能感兴趣的:(GEEKBAND C++ 面向对象高级编程(第四周))