1

I have an interesting problem to deal with. Is there any way to call derived class functions with base class pointer without virtual pointers? IMHO, I do not think so but would like to clear with experts.

Consider this example:

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
}

Is there any possible way? reinterpret_cast or anything else?

I do not want to use virtual since vptr comes into the picture and increases the memory by 8 bytes(depends) per object. Very frequently, I can have big number of B type objects. Say, 1 million objects of B type, I do not want my program memory to go by 1m x 8 bytes. Instead, I would rather not have virutal/vptr in such huge cases.

I would be happy to write more details if needed.

Hemant Bhargava
  • 3,251
  • 4
  • 24
  • 45
  • See also https://stackoverflow.com/questions/59087461/call-hidden-non-virtual-method-of-derived-class-from-base#comment104413245_59087461 – Max Langhof Dec 02 '19 at 09:20
  • 8
    Why don't you want to use virtual functions and the standard C++ polymorphism? What is the actual and underlying problem you need to solve with it? – Some programmer dude Dec 02 '19 at 09:20
  • @Someprogrammerdude, Can not use virtual. It would increase the program size by much since vptr comes into picture and 8 more bytes to the size. – Hemant Bhargava Dec 02 '19 at 09:24
  • Perhaps you could make a wrapper containing a pointer to the derived class´s `vtable`. That would require finding a way to have the compiler produce a `vtable` without using `virtual`, and also get access to it. – Andreas is moving to Codidact Dec 02 '19 at 09:25
  • @HemantBhargava You won't get around increasing the program size. The only remotely useful alternative is CRTP, which creates a complete copy of the base class code for every derived class (and also requires your base class to be a template, i.e. in a header). A vtable is orders of magnitude smaller. – Max Langhof Dec 02 '19 at 09:28
  • 4
    On a modern PC-type system such memory micro-optimizations are rarely if ever needed. You might want to edit your question to include details about why you can't use virtual functions, like platform or memory constraints, as otherwise people will generally tell you to not bother and just use virtual functions. – Some programmer dude Dec 02 '19 at 09:28
  • 4
    @HemantBhargava There are **very** few situations where the object size increase due to virtual functions is relevant. But, more fundamentally, other ways of achiving similar results (e.g. via function pointers) will *also* increase your object size by at least the same. – Konrad Rudolph Dec 02 '19 at 09:30
  • 2
    Also, without `virtual` you won't get RTTI, so it's literally impossible to tell at run-time whether a given `Base` pointer is of a given derived type - unless you add some per-object information, which is (due to alignment/padding) almost guaranteed to be 8 bytes in size, so you'd gain nothing. – Max Langhof Dec 02 '19 at 09:32
  • @KonradRudolph, Your answer is in the edited question. I have to bother about virtuals in big big cases. – Hemant Bhargava Dec 02 '19 at 09:38
  • If you don't want the overhead of polymorphism (vtable, etc), don't use it. Else you should accept it. It's not as bad as you might think it is. – JHBonarius Dec 02 '19 at 09:39
  • @MaxLanghof, Yeah. That is true. I was hoping if there is any way ever. – Hemant Bhargava Dec 02 '19 at 09:39
  • 3
    This looks like [XY-Problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). There are several ways to achive this but depends on the program architecture. 1. [Propagate the hidden methods](https://stackoverflow.com/questions/20571818/best-way-to-call-hidden-base-class-method) to derived (probably fits best your example?). 2. [Use Composition over Inheritance](https://en.wikipedia.org/wiki/Composition_over_inheritance). 3. [Use compiletime polymorphism](https://stackoverflow.com/questions/2128838/compile-time-polymorphism-and-runtime-polymorphism). – user1810087 Dec 02 '19 at 09:39
  • Please try to explain your underlying problem; the code as shown doesn't make much sense. There are probably dozens of ways to approach this. Without knowing what you want to achieve it's impossible to narrow this down. – Daniel Jour Dec 02 '19 at 12:02
  • 2
    Are `a` and `b` in the base class and in the dervied class the same? Do you use both `a` and `b` from the base class in the derived class? – Mike van Dyke Dec 02 '19 at 12:44
  • @DanielJour, Thanks for your reply. Is there any specific thing you want to know? – Hemant Bhargava Dec 03 '19 at 08:49
  • @MikevanDyke, No they are not same. They are different. No to the second question. – Hemant Bhargava Dec 03 '19 at 08:51
  • If you don't use `a` and `b` in the derived class, why don't you? you could avoid the use of `c` and `d` then and it saves you more memory, and that's what you want isn't it? – Mike van Dyke Dec 03 '19 at 09:42

2 Answers2

1

You can write:

Base* b = new Derived;

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

Of course, this would cause undefined behaviour if you tried it on a b that did not actually point to a Derived or child class of such. If you are in general not sure what the pointer points to, and you don't want to use vtables, you'll need to manually implement something to give you that information (e.g. a member variable of Base with type information).

M.M
  • 138,810
  • 21
  • 208
  • 365
  • O.P. is to access derived class member functions using base class pointers, not with derived class pointers. – Hemant Bhargava Dec 04 '19 at 04:38
  • @HemantBhargava The base class pointer is used in my code , the operation of accessing the function involves a cast and a dereference – M.M Dec 04 '19 at 04:50
0

Since I could not get any answer from anyone, let me float an option here which I have thought of. This might be a hack though. I am open for correction/comments and criticism as well. :)

The deal is to do reinterpret_cast in the base class functions.

#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;
  }

}

The output of this would be:

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()
Hemant Bhargava
  • 3,251
  • 4
  • 24
  • 45
  • 1
    This approach is not at all safe. If you call `get_a` or `get_b` on an object of the base class by accident after you have set `preState = false`, you get undefined behaviour. – Mike van Dyke Dec 03 '19 at 09:41
  • `__attribute__ ((__packed__))` is undefined behaviour, also the reinterpret_cast will fail for multiple inheritance – M.M Dec 03 '19 at 10:23
  • @MikevanDyke Thanks for your concern. However, I do make sure that it would not happen. – Hemant Bhargava Dec 04 '19 at 04:36