Nisba
Nisba

Reputation: 3458

Access methods of subclass from an instance casted to a pointer to base class

I have two classes A and B which derive from the same base class Base. I am defining in main a vector Base * and I use it for storing elements both of A and B. Using a reinterpret_cast I am able to call methods of their real class. Is this code safe? Is there a better/standard way of doing that?

The two classes in the real code share most of the methods from the base class but the A possesses some methods not shared with Base or B and the same for B, so virtual is not an option.

#include <iostream>
#include <vector>

class Base {
};

class A : public Base {
public:
    void print_from_A() {
        std::cout << "hello from A\n";
    }
};

class B : public Base {
public:
    int number;
    void read_from_B() {
        std::cin >> number;
    }
};

int main(int argc, char * argv[]) {
    std::vector<Base*> v;
    v.push_back(new A());
    v.push_back(new B());

    (reinterpret_cast<A *>(v[0]))->print_from_A();
    (reinterpret_cast<B *>(v[1]))->read_from_B();

    for(auto && e: v) {
        delete e;
    }
    return 0;
}

EDIT:

It seems that using reinterpret_cast is undefined behaviour: Casting to one class and calling function from sibling class?

It also seems that the correct way is using a static_cast: Can I get polymorphic behavior without using virtual functions?

Is this the answer?

Upvotes: 1

Views: 124

Answers (1)

R Sahu
R Sahu

Reputation: 206747

Is there a better/standard way of doing that?

  1. It is better to use a virtual member function.

  2. If you are not able to use a virtual member function, perform a dynamic_cast, check the status of the cast, and call the member function only if the cast succeeds.

Please note that the base class needs to have a virtual member function for dynamic_cast to work. In such cases, it is is recommended to make at least the destructor a virtual member function.

Here's an updated version of your program using virtual member functions:

#include <iostream>
#include <vector>

class Base {
   public:
      virtual ~Base() {}
      virtual void print() const = 0;
      virtual void read() = 0;
};

class A : public Base {
public:
    virtual void print() const {
        std::cout << "hello from A\n";
    }
   virtual void read() 
   {
      // Nothing to do.
   }
};

class B : public Base {
public:
    int number;
    virtual void print() const {
        std::cout << "hello from B, " << number << "\n";
    }
    virtual void read() {
        std::cin >> number;
    }
};

int main(int argc, char * argv[]) {
    std::vector<Base*> v;
    v.push_back(new A());
    v.push_back(new B());

    v[0]->read();
    v[0]->print();
    v[1]->read();
    v[1]->print();

    for(auto && e: v) {
        delete e;
    }
    return 0;
}

Upvotes: 1

Related Questions