c++ - 继承(C++)

标签 c++ inheritance

<分区>

假设在 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 函数。

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

关于c++ - 继承(C++),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29785643/

相关文章:

c++ - 如何获取内存区域的保护标志,标志是mprotect中的PROT_READ/PROT_EXEC

c++ - 做一个有潜在溢出的乘法然后用除法验证有什么问题吗?

C++/A 类 : public B, 公共(public) C/~C() 上的 B 发生了什么?

scala - 还有什么是Scala惯用: trait TraitA extends TraitB or trait TraitA { self: TraitB => }

c++ - 在函数调用时获取堆栈溢出

c++ - 在 MFC/Visual C++ 中覆盖 OnCancel 按钮

c++ - 限制函数执行时间

Javascript 继承最佳策略

c++ - 为从其模板成员函数调用中已知的类型创建新容器的类

c++ - CRTP继承中的基类 "friending"是否也会影响子类?