有没有一种方法可以使用基类指针调用派生类函数而没有虚拟

时间:2019-12-02 09:17:56

标签: c++

我有一个有趣的问题要处理。有没有办法在没有虚拟指针的情况下使用基类指针来调用派生类函数?恕我直言,我不这么认为,但想与专家们澄清。

考虑以下示例:

class B {
   public:
     int a;
     int b;
     int get_a() { return a };
     int get_b() { return b };
     B() : a(1), b(2) { }
};

class D : public B {
   public:
     int a;
     int b;
     int get_a() { return a };
     int get_b() { return b };
     D() : a(3), b(4) { }
};

int main() {
   Base* b = new Base;
   std::cout << b->get_a() << std::endl; // Gives 1
   std::cout << b->get_b() << std::endl; // Gives 2

    // Do something here which instantiates Derived and can call Derived functions using base class pointers.

    // Maybe Base\* b = new Derived();

   // But doing b->get_a() should call Derived class function get_a. 

   std::cout << <some_base_class_pointer_after_doing_something>->get_a() << std::endl; // Should give 3
   std::cout << <some_base_class_pointer_after_doing_something>->get_b() << std::endl; // Should give 4
}

有什么可能的方法吗? reinterpret_cast还是其他?

我不想使用虚拟,因为vptr进入了图片并且将每个对象的内存增加了8个字节(取决于)。很多时候,我可以拥有大量的B型对象。假设有100万个B类型的对象,我不希望我的程序内存增加1m x 8字节。相反,我宁愿在如此大的情况下也不要使用virutal / vptr。

如果需要,我很乐意写更多的细节。

2 个答案:

答案 0 :(得分:0)

由于我无法从任何人那里得到任何答案,所以让我在这里浮动一个我已经想到的选项。虽然这可能是一个hack。我也乐于接受纠正/评论和批评。 :)

要做的是在基类函数中进行reinterpret_cast。

#include <iostream>
#include <vector>

bool preState = true;
class Derived;
class Base;

class Base {
  public:
  unsigned char a;
  int b;
  Base() : a('a'), b (2) { };
  unsigned char get_a() const;
  int get_b() const;
} __attribute__ ((__packed__)) ;

class __attribute__ ((__packed__)) Derived : public Base {
  public:
  unsigned char c;
  int d;
  Derived() : c('c'), d(4) { };

  unsigned char get_a() const;
  int get_b() const;
};

unsigned char Base::get_a() const {
  if (preState) {
    return a;
  } else {
    const Derived* d = reinterpret_cast<const Derived*>(this);
    return d->get_a();
  }
}

int Base::get_b() const {
  if (preState) {
    return b;
  } else {
    const Derived* d = reinterpret_cast<const Derived*>(this);
    return d->get_b();
  }
}

unsigned char Derived::get_a() const {
  return c;
}

int Derived::get_b() const {
  return d;
}

int main() {
  std::vector<Base*> bArray;
  bArray.push_back(new Base());
  bArray.push_back(new Base());

  std::vector<Base*>::iterator bArrayIt = bArray.begin();
  for (; bArrayIt != bArray.end(); ++bArrayIt) {
    std::cout << (*bArrayIt)->get_a() << " ";
    std::cout << (*bArrayIt)->get_b() << std::endl;
  }

  preState = false;

  std::vector<Base*> dArray;
  bArrayIt = bArray.begin();
  for (; bArrayIt != bArray.end(); ++bArrayIt) {
    // Write copy constructor in Derived class which copies everything from 
    // base object to Derived object
    Base* b = new Derived(); 
    dArray.push_back(b);
  }

  std::vector<Base*>::iterator dArrayIt = dArray.begin();
  for (; dArrayIt != dArray.end(); ++dArrayIt) {
    std::cout << (*dArrayIt)->get_a() << " ";
    std::cout << (*dArrayIt)->get_b() << std::endl;
  }

}

其输出为:

a 2 // Base class get_a() and get_b()
a 2 // Base class get_a() and get_b()
c 4 // Derived class get_a() and get_b()
c 4 // Derived class get_a() and get_b()

答案 1 :(得分:0)

您可以写:

Base* b = new Derived;

Derived *d = static_cast<Derived *>(b);
std::cout << d->get_b() << '\n';

当然,如果您在b上尝试使用它实际上未指向此类的Derived或子类,则会导致未定义的行为。如果您总体上不确定指针指向什么,并且不想使用vtables,则需要手动实施一些操作以向您提供该信息(例如,Base的成员变量具有类型信息) )。