Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create a variable to hold objects of different types C++

I have 3 different objects A, B and C. Depending on the the parameter given, I would like to choose among these different objects. In programming,

class A { 
  public: 
    void printHello() { cout << "HELLO A" << endl; }
}; 

class B { 
  public: 
    void printHello() { cout << "HELLO B" << endl; }  
};

class C { 
   public: 
     void printHello() { cout << "HELLO C" << endl; }  
}; 

int main () { 
    string key = "c"; 
    A a; 
    B b; 
    C c; 
    Object obj; // I don't know how to declare Object. 

    if (key == "a") obj = a; 
    else if (key == "b") obj = b; 
    else obj = c;
    obj.printHello(); // print Hello C.
    return 0; 
} 

I have thought about templates and struct objects. But none of them work so far.

template<typename T1, T2, T3> 
T1 getType(string key, T1 t1, T2 t2, T3 t3) { // this is problem coz return types are different.
    if (key == "a") return t1; 
    else if (key == "b") return t2; 
    else return t3; 
} 

It is easy to create Object o; in JAVA because every object in Java is subclass of Object class. But how do I achieve this in C++?

Edit. I can't change class A, B and C. I was given these classes to work with and my goal is to implement main method. So, inheritance was out of the question for me. Sorry for any confusion.

Any help is appreciated.

like image 388
pseudo Avatar asked Feb 05 '23 18:02

pseudo


2 Answers

You're looking for a variant type. There's an upcoming std::variant in C++17, and C++11-compliant versions in boost and around the web. Example with boost::variant:

struct visitor
{
    void operator()(const A&){ cout << "HELLO A" << endl; }
    void operator()(const B&){ cout << "HELLO B" << endl; }
    void operator()(const C&){ cout << "HELLO C" << endl; }
};

int main()
{
    visitor v;

    // `obj` is either an `A`, a `B` or a `C` at any given moment.
    boost::variant<A, B, C> obj{B{}};
    //                         ^^^^^
    //                   Initialize with `B`.

    boost::apply_visitor(v, obj); // prints "HELLO B"

    obj = A{};
    boost::apply_visitor(v, obj); // prints "HELLO A"
}
like image 141
Vittorio Romeo Avatar answered Feb 07 '23 09:02

Vittorio Romeo


It seems to me that you should use a virtual common base class/struct and a pointer to this base class/struct.

The following is a full working example

#include <iostream>

struct Base
 { virtual void printHello () = 0; };

class A : public Base { 
  public: 
    void printHello() { std::cout << "HELLO A" << std::endl; }
}; 

class B  : public Base{ 
  public: 
    void printHello() { std::cout << "HELLO B" << std::endl; }  
};

class C  : public Base{ 
   public: 
     void printHello() { std::cout << "HELLO C" << std::endl; }  
}; 

int main () { 
    std::string key = "c"; 
    A a; 
    B b; 
    C c; 
    Base * obj; 

    if (key == "a") obj = &a; 
    else if (key == "b") obj = &b; 
    else obj = &c;
    obj->printHello(); // print Hello C.
    return 0; 
} 
like image 33
max66 Avatar answered Feb 07 '23 09:02

max66