面试题答案
一键面试动态绑定和静态绑定的区别
- 静态绑定:
- 概念:在编译期确定函数调用的具体目标。编译器根据对象的声明类型(即定义对象时使用的类型)来决定调用哪个函数。
- 特点:效率高,因为在编译时就确定了函数地址,无需运行时额外的查找开销。但灵活性较差,不能根据对象实际类型进行函数选择。
- 动态绑定:
- 概念:在运行期确定函数调用的具体目标。它根据对象的实际类型(在运行时确定的对象类型)来决定调用哪个虚函数的实现。
- 特点:灵活性高,能够根据对象实际类型做出正确的函数调用,实现多态性。但由于需要在运行时通过虚函数表等机制查找函数地址,有一定的性能开销。
发生静态绑定而非动态绑定的情况及代码示例
- 非虚函数调用:
- 当调用的函数不是虚函数时,发生静态绑定。
#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
对象。
- 通过对象调用虚函数:
- 当通过对象(而非指针或引用)调用虚函数时,发生静态绑定。
#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
是虚函数,但baseObj
是Base
类型的对象,derivedObj
赋值给baseObj
时发生了切片,丢失了Derived
类的额外信息,所以调用的是Base
类中的virtualFunction
。
- 在构造函数和析构函数中调用虚函数:
- 在构造函数和析构函数中调用虚函数时,发生静态绑定。
#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
。