VTable和多态性

Eya*_*yal 5 c++ inheritance vtable

在阅读了很多关于VTables之后,我仍然有一个悬而未决的问题.

鉴于下一堂课:

#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;
    }
};
Run Code Online (Sandbox Code Playgroud)

以及以下测试:

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();
}
Run Code Online (Sandbox Code Playgroud)

我得到这个输出:

default Shape ctor
Circle constructor
size of *c is 12
size of *s is 8
print Circle. The number is 5
Run Code Online (Sandbox Code Playgroud)

我的问题是:我知道如何处理Circle :: draw,但是怎么知道变量b = 5?如本测试所示,s没有此信息.我在这里错过了什么?

谢谢!

好,朋友们.谢谢你的快速回答......

我从你的答案中得知,在Circle :: draw()(*this)中是Circle类型.好.我现在的问题已经变成这样:因为我只是想小号是一个Shape*类型,也就是说,我需要在我的程序只有外形气质.是否可能以某种方式由编译器接下来的4个字节(Circle中的b变量)?如果是这样,显然Circle :: draw()将无法正常工作..

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

Stu*_*etz 2

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

编辑:为了回答你的新问题,s是一个指向-Shape你所做的就是存储相同的地址(到Circle内存中对象的开头)但使用不同的类型(Shape*而不是Circle*)。Circle无论指向它的东西如何,底层对象都存在于内存中。您不能直接访问Circle特定的数据成员 through ,因为它是 a ,但虚拟调度机制意味着当您调用虚拟成员函数 through 时,该调用将转发到 中的相应成员函数,即实际上最终调用。由于将底层对象的地址存储在 a 中,底层对象不会以某种方式被“切片”,从而删除数据成员。仅当您执行此类操作时才会发生切片:sShape*sCircles->draw();Circle::drawCircleShape*Circleb

Circle c;
Shape s = c; // copies the Shape data members across from c, but slices off the rest
Run Code Online (Sandbox Code Playgroud)