Inheritance (c++)

Inheritance (c++)

本文关键字:c++ Inheritance      更新时间:2023-10-16

假设main中有一个派生类的实例。调用成员函数时,是调用基类中函数的版本,还是仅调用派生类中的重载版本?此外,如果基类的指针被初始化为指向构造函数运行的派生类的实例,如果有的话?

struct Base {
virtual ~Base() {}
void nonvirtual() {std::cout << "Base::nonvirtual()n";}
virtual void isvirtual() {std::cout << "Base::isvirtual()n";}
};
struct Derived : public Base {
virtual ~Derived() {}
void nonvirtual() {std::cout << "Derived::nonvirtual()n";}
virtual void isvirtual() {std::cout << "Derived::isvirtual()n";}
};

这里不可见的是,由于virtual成员的存在,编译器为类Base创建了一个函数表,其中有两个指针(每个虚拟函数一个),每个指针指向其中一个虚拟函数。编译器为派生函数创建一个几乎相同的表,它的两个指针指向这些函数的Derived版本。这个魔术还为每个类实例添加了一个"虚拟函数指针",它指向其中一个表。

int main() {
Derived d;
d.nonvirtual(); //this prints Derived::nonvirtual()
d.isvirtual(); //this prints Derived::isvirtual()
Base b;
b.nonvirtual(); //this prints Base::nonvirtual()
b.isvirtual(); //this prints Base::isvirtual()
}

这为main中的每个变量创建空间,并为每个变量调用默认构造函数。构造函数将不可见的虚拟函数指针设置为指向指向正确函数的表。所有显而易见的功能。

int main() {
Derived d;
Derived* dptr = &d;
dptr->nonvirtual(); //this prints Derived::nonvirtual()
dptr->isvirtual(); //this prints Derived::isvirtual()
Base* bptr = &d;
bptr->nonvirtual(); //this prints Base::nonvirtual()
bptr->isvirtual(); //this prints Derived::isvirtual() !!!!!!!
}

指针和引用是很棘手的地方。如果我们创建一个Derived*并将其指向Derived实例,它将继续表现得很明显。不是的是当Base*指向Derived实例时会发生什么。如果调用非虚拟成员函数,编译器会看到您使用的是Base指针,并使用该函数的Base版本。相对简单。如果Base中的成员函数是virtual,那么编译器的魔力就来了。它检查不可见的虚拟指针成员,并检查它指向的表。在这种情况下,它指向具有Derived成员函数的表。编译器知道isvirtual是第二个虚拟成员,所以它调用该表中的第二个函数,即Derived::isvirtual函数。

由于相关的原因,如果一个类可以用作基类,则应该几乎总是给它一个虚拟析构函数。