c++ - 虚表和多态性

标签 c++ inheritance vtable

在阅读了大量有关 VTable 的内容之后,我仍然有一个 Unresolved 问题。

给定下一节课:

#include <iostream>
using namespace std;

class Shape {
public:
    int* a;
    Shape(){
        cout<<"default Shape ctor"<<endl;
        a = new int(15); // default
    }
    Shape(int n){
        a = new int(n);
          cout<<"Shape(n) constructor"<<endl;
    }
    // copy constructor
    Shape(const Shape& s){
        cout<<"copy constructor"<<endl;
        a = new int(*(s.a));
    }
    Shape& operator=(const Shape& s){
        cout<<"operator="<<endl;

        if (&s == (this))
            return (*this);
//      this.clear();
        a = new int(*(s.a));

        return (*this);
    }


      virtual void draw(){
             cout<<"print Shape the number is "<<*a<<endl;
      };
      virtual ~Shape(){
          delete a;
          cout<<"Shape distructor"<<endl;
      }
};

class Circle : public Shape {
public:
    int b;
  Circle() {
      cout<<"Circle constructor"<<endl;
      b=5;
  }
  virtual void draw() {
      cout<<"print Circle. The number is "<<b<<endl;
  }
   ~Circle(){
      cout<<"Circle distructor"<<endl;
    }
};

和以下测试:

static void test2(){
    Circle* c = new Circle();
    cout<<"size of *c is "<<sizeof(*c)<<endl;
    Shape* s = c;
    cout<<"size of *s is "<<sizeof(*s)<<endl;
    s->draw();
}

我得到这个输出:

default Shape ctor
Circle constructor
size of *c is 12
size of *s is 8
print Circle. The number is 5

我的问题是:我知道 s 如何寻址 Circle::draw,但 s 如何知道变量 b=5? 如该测试所示,s 没有此信息。我在这里缺少什么?

谢谢!

好的伙计们。感谢您的快速回答...

我从您的回答中得知 Circle::draw() (*this) 是 Circle 类型。好的。 我的问题现在变成了:因为我只希望 s 是 Shape* 类型,也就是说,我的程序只需要 Shape 特性。接下来的 4 个字节(Circle 中的 b 变量)是否有可能被编译器以某种方式占用?如果是这样,显然 Circle::draw() 将无法按预期工作。

如果不是,编译器如何知道在 s 的“结束”之后我将需要接下来的 4 个字节?

最佳答案

您缺少的是 s 指向一个 Circle —— 而 Circle 包含一个名为 b 的数据成员。当调用 s->draw(); 时,编译器会调用 Circle::draw(),如您所见,并在 Circle::draw() 内*this(即当前对象)的类型是 Circle 而不是 Shape。所以 Circle::draw() 可以访问 b

编辑:在回答您的新问题时,s 是指向 Shape指针——您所做的只是存储相同的地址(到内存中 Circle 对象的开头)但具有不同的类型(Shape* 而不是 Circle*)。底层的 Circle 对象存在于内存中,与指向它的事物无关。您不能通过 s 直接访问 Circle 特定的数据成员,因为它是一个 Shape*,但是虚拟调度机制意味着当您调用通过 s 的虚拟成员函数,调用被转发到 Circle 中的适当成员函数,即 s->draw(); 实际上结束了调用 Circle::draw。没有危险,因为将底层 Circle 对象的地址存储在 Shape* 中,底层 Circle 对象将以某种方式 ' sliced',去掉 b 数据成员。切片仅在您执行此类操作时发生:

Circle c;
Shape s = c; // copies the Shape data members across from c, but slices off the rest

关于c++ - 虚表和多态性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5512058/

相关文章:

c++ - 虚拟表和 _vptr 存储方案

c++ - Direct2D C++ 用户输入

c++ - 无法编辑 TADOTable 中的数据

c# - 有没有办法调用重写方法的父版本? (C#.NET)

c++ - upcasting 和 vtables 如何协同工作以确保正确的动态绑定(bind)?

c++ - _declspec( novtable ) 什么时候不安全?

c++ - 尝试使用 vector<ostringstream> 时出现编译错误

c++ - CeilLog2函数中变量BitMask的实际作用是什么?

java - 在多个类中使用 Java 方法

c++ - 派生类构造函数可以继承c++中的基类构造函数吗?