1

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?

Nisba
  • 3,210
  • 2
  • 27
  • 46
  • 1
    Add a virtual destructor to `Base`, do downcasting using `dynamic_cast`, try not to do downcasting. – imreal Apr 17 '18 at 15:15

1 Answers1

1

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;
}
R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • Using a `dynamic_cast` I get the error 'Base' is not polymorphic – Nisba Apr 17 '18 at 15:17
  • 1
    @Nisba, 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. – R Sahu Apr 17 '18 at 15:19
  • It works great! Bonus question: will it work also with smart pointers? – Nisba Apr 17 '18 at 15:24
  • I found that there is a standard way to do this: http://en.cppreference.com/w/cpp/memory/shared_ptr/pointer_cast – Nisba Apr 17 '18 at 15:26
  • 1
    @Nisba, yes it will work with smart pointers, as you already figured it out. – R Sahu Apr 17 '18 at 15:28