MST
星途 面试题库

面试题:C++多态中的动态绑定与静态绑定

在C++多态机制下,详细解释动态绑定和静态绑定的区别,以及在什么情况下会发生静态绑定而非动态绑定,结合具体代码说明。
23.3万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

动态绑定和静态绑定的区别

  1. 静态绑定
    • 概念:在编译期确定函数调用的具体目标。编译器根据对象的声明类型(即定义对象时使用的类型)来决定调用哪个函数。
    • 特点:效率高,因为在编译时就确定了函数地址,无需运行时额外的查找开销。但灵活性较差,不能根据对象实际类型进行函数选择。
  2. 动态绑定
    • 概念:在运行期确定函数调用的具体目标。它根据对象的实际类型(在运行时确定的对象类型)来决定调用哪个虚函数的实现。
    • 特点:灵活性高,能够根据对象实际类型做出正确的函数调用,实现多态性。但由于需要在运行时通过虚函数表等机制查找函数地址,有一定的性能开销。

发生静态绑定而非动态绑定的情况及代码示例

  1. 非虚函数调用
    • 当调用的函数不是虚函数时,发生静态绑定。
    #include <iostream>
    class Base {
    public:
        void nonVirtualFunction() {
            std::cout << "Base::nonVirtualFunction" << std::endl;
        }
    };
    class Derived : public Base {
    public:
        void nonVirtualFunction() {
            std::cout << "Derived::nonVirtualFunction" << std::endl;
        }
    };
    int main() {
        Base* basePtr = new Derived();
        basePtr->nonVirtualFunction(); // 这里发生静态绑定,调用Base::nonVirtualFunction
        delete basePtr;
        return 0;
    }
    
    • 在上述代码中,nonVirtualFunction不是虚函数,basePtr声明为Base*类型,所以调用的是Base类中的nonVirtualFunction,即使basePtr实际指向的是Derived对象。
  2. 通过对象调用虚函数
    • 当通过对象(而非指针或引用)调用虚函数时,发生静态绑定。
    #include <iostream>
    class Base {
    public:
        virtual void virtualFunction() {
            std::cout << "Base::virtualFunction" << std::endl;
        }
    };
    class Derived : public Base {
    public:
        void virtualFunction() override {
            std::cout << "Derived::virtualFunction" << std::endl;
        }
    };
    int main() {
        Derived derivedObj;
        Base baseObj = derivedObj;
        baseObj.virtualFunction(); // 这里发生静态绑定,调用Base::virtualFunction
        return 0;
    }
    
    • 在上述代码中,virtualFunction是虚函数,但baseObjBase类型的对象,derivedObj赋值给baseObj时发生了切片,丢失了Derived类的额外信息,所以调用的是Base类中的virtualFunction
  3. 在构造函数和析构函数中调用虚函数
    • 在构造函数和析构函数中调用虚函数时,发生静态绑定。
    #include <iostream>
    class Base {
    public:
        Base() {
            virtualFunction();
        }
        virtual void virtualFunction() {
            std::cout << "Base::virtualFunction" << std::endl;
        }
        ~Base() {
            virtualFunction();
        }
    };
    class Derived : public Base {
    public:
        Derived() {
            virtualFunction();
        }
        void virtualFunction() override {
            std::cout << "Derived::virtualFunction" << std::endl;
        }
        ~Derived() {
            virtualFunction();
        }
    };
    int main() {
        Base* basePtr = new Derived();
        delete basePtr;
        return 0;
    }
    
    • 在构造Derived对象时,先调用Base的构造函数,此时Derived部分还未构造完成,所以在Base构造函数中调用virtualFunction是静态绑定,调用的是Base::virtualFunction。析构函数同理,在Derived析构函数调用Base析构函数时,Derived部分已析构,此时调用virtualFunction也是静态绑定,调用Base::virtualFunction