2

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.

17
  • 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? Commented Dec 2, 2019 at 9:20
  • 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. Commented Dec 2, 2019 at 9: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. Commented Dec 2, 2019 at 9: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. Commented Dec 2, 2019 at 9:32
  • 3
    This looks like XY-Problem. There are several ways to achive this but depends on the program architecture. 1. Propagate the hidden methods to derived (probably fits best your example?). 2. Use Composition over Inheritance. 3. Use compiletime polymorphism. Commented Dec 2, 2019 at 9:39

2 Answers 2

2

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).

Sign up to request clarification or add additional context in comments.

2 Comments

O.P. is to access derived class member functions using base class pointers, not with derived class pointers.
@HemantBhargava The base class pointer is used in my code , the operation of accessing the function involves a cast and a dereference
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()

3 Comments

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.
__attribute__ ((__packed__)) is undefined behaviour, also the reinterpret_cast will fail for multiple inheritance
@MikevanDyke Thanks for your concern. However, I do make sure that it would not happen.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.