How to « reverse » inheritance when working with polymorphism? - c++

I have a working design in C++, just like the following :
struct E {
int some_properties ;
// … some more
};
class A {
public:
void tick() {
std::swap(futur, past) ;
}
void do_something() {
// do something (read past, write futur)
futur->some_properties = past->some_properties + 1 ;
}
E* past ;
protected:
E* futur ;
};
Now, I'd like to both create a class B which inherit class A with a new void do_other_thing() method and a struct F which inherit struct E with a new int some_other ; attribute.
The method void do_other_thing() could be for example :
void do_other_thing() {
// do something (read past, write futur)
futur->some_properties = past->some_properties + past->some_other ;
futur->some_other = past->some_other + 1 ;
}
I'm very confused about how to achieve this inheritance.
Especially when it comes to achieve this kind of use case :
// A a ;
a.tick() ;
a.do_something() ;
And :
// B b ;
b.tick()
b.do_something() ;
b.tick() ;
b.do_other_thing() ;
Here comes the question :
Is this even possible ?
If yes, how ?
If not, how to solve the problem with a better stucture ?
EDIT:
As answered, the simplest inheritance pattern will be:
class B : public A {
void do_other_thing(){ // Something }
}
struct F : public E {
int some_other;
}
The problem encountered is that past and futur here are E pointers:
void do_other_thing() {
// do something (read past, write futur)
futur->some_properties = past->some_properties + past->some_other ;
futur->some_other = past->some_other + 1 ;
}

You could dynamic_cast:
void do_other_thing() {
F* futur_f = dynamic_cast<F*>(futur);
F* past_f = dynamic_cast<F*>(past);
assert(futur_f && past_f);
futur_f->some_properties = past_f->some_properties + past_f->some_other ;
futur_f->some_other = past_f->some_other + 1 ;
}
or you could use a second pair of pointer members in B which point to the same objects as futur and past (more data, less casting - essentially caching the runtime cast)
or you could use a template base class where the type of past and futur is a template parameter (sometimes requires the introduction of a non-templated "root class" and making everything virtual).
And probably quite a few other ways, with varying trade-offs, benefits, and complications.
What to choose depends on the rest of your program and your personal preferences.

First, yes it is possible. The following is just pseudo-code for illustration:
class B : public A {
void do_other_thing(){ std::cout << "Other" << std::endl; }
}
struct F : public E {
int some_other;
}
Now both of these new types will follow the principle of being able to take the place of their parent types. This is achieved by referring to the sub-types by a pointer to their base types (polymorphism).
std::shared_ptr<A> baseARefToB{ std::make_shared<B>() };
baseRefToB->do_something();
std::shared_ptr<E> baseERefToF{ std::make_shared<F>() };
baseERefToF->some_properties = 3;
Note that I cannot access their sub-class methods and properties via the base class references. BUT:
std::static_pointer_cast<B>(baseRefToB)->do_other_thing();
std::static_pointer_cast<E>(baseERefToF)->some_other = 42;
Here I have cast the references to their base types so I can access their sub-class specific functionality.
So from your problem description you will be able (always) to call the base class functionality (do_something and some_properties) for all types of A and E, but you will only be able to access the sub-class functionality if you refer to the object via pointers with the correct type.

Related

C++ Lookup table for derived classes

I have a wrapper class holding a bunch of derived class objects by means of a vector of references to a common base class. During runtime, the Child objects are created based on user input.
#include <iostream>
#include <vector>
#include <memory>
#include <type_traits>
class Base {
public:
virtual void run() = 0;
};
class Wrapper {
public:
std::vector<std::shared_ptr<Base>> blocks;
template <class Child>
auto create() -> std::shared_ptr<Child>
{
auto block = std::make_shared < Child > ();
blocks.emplace_back(block);
return std::move(block);
}
template <typename A, typename B>
void connect(A a, B b)
{
using connectionType = typename A::element_type::out;
connectionType* port = new connectionType;
a.get()->ptr_out = port;
b.get()->ptr_in = port;
}
};
class Child_1 : public Base {
public:
using in = int;
using out = float;
out* ptr_out;
in* ptr_in;
void run() { std::cout<<"running child 1\n"; *ptr_out = 1.234;};
};
class Child_2 : public Base {
public:
using in = float;
using out = bool;
out* ptr_out;
in* ptr_in;
void run() { std::cout<<"running child 2\ngot: "<<*ptr_in; };
};
int main () {
Wrapper wrapper;
/* read config file with a list of strings of which types to create */
std::vector < std::string > userInput;
userInput.push_back("Type 0");
userInput.push_back("Type 1");
for (auto input:userInput)
{
if (input == "Type 0")
wrapper.create < Child_1 > ();
else if (input == "Type 1")
wrapper.create < Child_2 > ();
/* and so on */
}
/* read config file with a list of pairs of which objects to connect */
std::vector < std::pair < int, int >>connections;
connections.push_back(std::make_pair(0, 1));
// e.g. user wants to connect object 0 with object 1:
for (int i = 0; i < connections.size (); i++)
{
auto id0 = connections[i].first; // e.g. 0
auto id1 = connections[i].second; //e.g. 1
// this will not work because Base has no typename in / out:
// wrapper.connect (wrapper.blocks[id0], wrapper.blocks[id1]);
// workaround:
wrapper.connect(
std::dynamic_pointer_cast<Child_1>(wrapper.blocks[id0]),
std::dynamic_pointer_cast<Child_2>(wrapper.blocks[id1]));
}
wrapper.blocks[0].get()->run();
wrapper.blocks[1].get()->run();
return 0;
}
Now, I'm only able to store a vector of Base objects which cannot hold the different in/out types of each derived object. When I want to connect the derived objects (which are stored as Base class objects), I need to dynamic_pointer_cast them back into their derived class. What's the most efficient way to do this?
There are a few ways I could think of - none of which seem to be possible (to my knowledge) with C++:
Have some kind of lookup-table / enum which returns a type to cast to; I could then create a map from the user input "Type 0" etc to the type and cast accordingly.
Have some kind of lambda-like expression that would return the correctly casted pointer type such that I can call wrapper.connect( lambda_expression(...), lambda_expression(...) ).
Brute force: check for each possible combination of user inputs and call the connect function with the dynamic_pointer_cast (as shown in the coding example). This will very likely not be suitable for my real-world application (currently using about 25 such classes) because it would result in a huge number of not maintainable function calls...
Somehow give the generic in/out types to the Base class but I can't think of any method to do so.
I really hope I'm missing something obvious. Any help is much appreciated.
This looks like a typical case of double dynamic dispatching, however there is a possible simplification in that the output and input types must match. Hence, here is sort of a half-Visitor pattern.
First, we extract the concepts of input and output types into classes so that they can be targeted by dynamic_cast:
template <class In_>
struct BaseInput {
using In = In_;
std::shared_ptr<In> ptr_in;
};
template <class Out_>
struct BaseOutput {
using Out = Out_;
std::shared_ptr<Out> ptr_out;
};
Note: I've swapped in std::shared_ptrs rather than letting raw owning pointers in the wild.
From there, we can declare a virtual connectTo function in Base to get the first level of dynamic dispatching:
class Base {
public:
virtual ~Base() = default;
virtual void run() = 0;
virtual void connectTo(Base &other) = 0;
};
Note: I have added a virtual destructor to Base. AFAICT it is superfluous thanks to std::shared_ptr's type erasure, however Clang was spewing warnings at me and I wasn't willing to chase them down.
Finally, the second dynamic lookup can be done from Base::connectTo's override, which I have factored out in a handy template:
template <class In, class Out>
struct Child
: Base
, BaseInput<In>
, BaseOutput<Out> {
void connectTo(Base &other_) override {
// Throws std::bad_cast if other_'s input type doesn't match our output type
auto &other = dynamic_cast<BaseInput<Out> &>(other_);
this->ptr_out = other.ptr_in = std::make_shared<Out>();
}
};
At that point a Visitor pattern would swap the objects around and perform a second virtual call from other_ to get the second dynamic dispatch. However, as mentioned above, we know exactly what type we're looking for, so we can just dynamic_cast to reach it.
Now we can implement Wrapper::connect as simply:
template < typename A, typename B > void connect (A a, B b)
{
a.get()->connectTo(*b.get());
}
... and define child classes this way:
class Child_1 : public Child<int, float> {
public:
void run() { std::cout<<"running child 1\n"; *ptr_out = 1.234;};
};
See it live on Wandbox

Boost ptr_list accessing subclass methods

To start out, I am just returning to c++ from a 20 or so year absence. I am just working to figure out some stuff. I want to create a class hierarchy and instantiate subclasses of a base class into a list and iterate on the list and get the subclass back in the iterator or find a way to accomplish this.
namespace FooBar {
class ace {
public: ace::ace(){};
public: virtual int ace::getValue(){ return 1; };
};
class base : public ace {
public: base::base(){};
**// Added method for casting
public: base::base(ace){};**
public: int base::getValue(){ return 2; };
};
class face : public ace {
public: face::face(){};
**// Added method for casting
public: face::face(ace){};**
public: int face::getValue(){ return 3; };
};
}
I create instances of the appropriate sub class to insert on the list. I can't sort out how to get the sub class back from the iterator. I've tried adding an identifier so I would know which class it was, but I can't work out how to cast the iterator.
int main() {
using namespace FooBar;
boost::ptr_list<ace> theList;
for (int i = 0; i < 10; i++){
ace* foo;
if (i % 2 == 0)
foo = new base();
else
foo = new face();
theList.push_back(foo);
}
for (boost::ptr_list<ace>::iterator iter = theList.begin(); iter != theList.end(); iter++){
std::cout << (*iter).getValue() << ", ";
// cast to sub class; Is it of type base
if (typeid(base) == typeid(*iter)){
base bar = static_cast<base>(*iter);
}
else {typeid(face) == typeid(*iter)){
face bar = static_cast<face>(*iter);
}
}
}
the output is 1, 1, ...
Both casts above fail with no suitable user-defined conversion from ace to base/face exists;
So, I created a constructor for both base and face as shown in added comment;
and the error I now get is
ace::ace(const ace &) cannot be references it is a deleted function.
Any guidance would be appreciated.
I can't sort out how to get the sub class back from the iterator
You can't, the way you currently have it set up. C++ has no run time type information (rtti) except for classes which are polymorphic (classes which have at least one virtual function).
You can make getValue virtual (just write virtual before it), and not need to get a pointer to the derived class from a pointer to the base class. That would be the idiomatic solution here.
If you actually had a case you needed to get a derived type from a base type pointer (and the class had a virtual function) you can either use dynamic_cast or a combination of typeid and static_cast to figure out what the derived type is.

Pointer to a Class Type

Essentially I'm trying to work around the problem of not being able to store derived types as a derived type in a (value) array of a base type. I have multiple classes that store one to three ints but have to have very different sets of functions. I'd use an array of pointers but the entire array is traversed forwards, then backwards constantly, mostly linearly, so keeping it all together in memory is preferable. I could create multiple arrays, one for each type and then an array of pointers to each of those, but that would get pretty clumsy fast and really wouldn't be the same as each element packed neatly between the one preceding it and the one proceeding it in order of access at runtime.
So what I'm thinking is that I make a POD struct with three ints and a pointer and fill an array with those, then use that pointer to access polymorphic functions. It would end up something along these lines: (forgive the poor coding here, I'm just trying to convey the concept)
class A {
int aa( &foo f ) { return 1; }
int dd() { return 9; }
};
class B : A {
int aa( &foo f ) { return f.b; }
};
class C : A {
int aa( &foo f ) { return cc() + f.c - f.a; }
int cc() { return 4; }
};
class D : B {
int dd() { return 7; }
};
struct foo{ int a, b, c; A* ptr; };
const A AA = A(); const B BB = B(); const C CC = C(); const D DD = D();
foo[100] foos;
init() {
foo[0] = foo{ 1, 2, 3, &BB };
// etc fill foos with various foo elements
}
bar(){
for ( int i = 0; i < 100; ++i ){
print foos[i].ptr.aa( &foos[i] );
print foos[i].ptr.dd();
}
}
main(){
init();
while(true)
bar();
}
I'm just wondering if this is the best way to go about what I want to achieve or if there's a better solution? Ideally I'd just point to a class rather than an instance of a class but I don't think I can really do that... ideally I'd store them in an array as multiple derived types but for obvious reasons that's not going to fly.
What you are looking for are virtual functions.
In the bellow example :
class A
{
virtual void foo(){printf("A is called");};
}
class B : public A
{
void foo(){printf("B is called");};
}
...
A* ptr = new B();
ptr->foo();
Will produce "B is called" .
If you don't want to use virtual functions (to save memory for example), you can use dynamic cast , but this will lead to significant performance loss.
Please not that you need to have at least 1 virtual function to perform dynamic cast.
In the example bellow :
class A {...}
class B : public A {...}
class C : public A {...}
A* ptr1 = new C();
B* ptr2 = dynamic_cast<B*>(ptr1);
C* ptr3 = dynamic_cast<C*>(ptr1);
ptr2 will be null, and ptr3 will have a value.
So you can make the following (very wrong) construct :
if (ptr2)
{
ptr2->bb();
} else if (ptr3)
{
ptr3->cc();
}
Finally, you can get rid of dynamic casting by having your own typing mechanism and then just C cast to the correct class.
You need polymorphism. In your example all the classes have standard methods. You need to make them virtual, so the polymorphism can be applied.
class A {
virtual int aa( foo& f )const { return 1; }
virtual int dd()const { return 9; }
};
class B : A {
virtual int aa( foo& f )const { return f.b; }
};
class C : A {
virtual int aa( foo& f )const { return cc() + f.c - f.a; }
int cc()const { return 4; }// this doesn't need to be virtual because is not in the base class A
};
class D : B {
virtual int dd()const { return 7; }
};
Here is some information on this topic: http://www.cplusplus.com/doc/tutorial/polymorphism/. There is some information on how to use pointers as well.
I would suggest to look at smart pointers: http://www.cplusplus.com/reference/memory/shared_ptr/?kw=shared_ptr
Another topic you should look at is constness: search for "constness c++" (cannot post more then 2 links)
struct foo{ int a, b, c;const A* ptr; }; // const A* instead of A*
... I'm trying to work around the problem of not being able to store derived types as a derived type in a (value) array of a base type.
You can store derived types, as values, in an array - you just can't store them as instances of the base type.
A union of your concrete leaf types is almost what you want, but there's no way to figure out which member of the union is live, or to use polymorphic dispatch.
A discriminated union is one which tells you which member is live, but doesn't directly help with the dispatch.
Boost.Variant is a specific discriminated union which provides a clean mechanism for polymorphic dispatch - not using virtual, but using a visitor with overloads for each concrete stored type. In this case, you don't even need the stored types to be related to a common abstract base - they can be entirely unrelated. Look for apply_visitor in the tutorial for details.

One pointer, two different classes in c++

Suppose I have two structures a and b, each hold several variable in them (most of the variable are c++ core types but not all).
Is there a way to create a a pointer named c that can point to either one of them? Alternatively, is there a way to create a set that can hold either one of them?
Thanks
The usual way to create a pointer that can point to either of the two is to make them inherit from a common base-class. Any pointer of the base-class can point to any sub-class. Note that this way you can only access elements that are part of the base-class through that pointer:
class Base {
public:
int a;
};
class Sub1 : public Base {
public:
int b;
};
class Sub2 : public Base {
public:
int c;
};
int main() {
Base* p = new Sub1;
p.a = 1; // legal
p.b = 1; // illegal, cannot access members of sub-class
p = new Sub2; // can point to any subclass
}
What you are trying to achieve is called polymorphism, and it is one of the fundamental concepts of object oriented programming. One way to access member of the subclass is to downcast the pointer. When you do this, you have to make sure that you cast it to the correct type:
static_cast<Sub1*>(p).b = 1; // legal, p actually points to a Sub1
static_cast<Sub2*>(p).c = 1; // illegal, p actually points to a Sub1
As for your second question, using the technique described above, you can create a set of pointers to a base-class which can then hold instance of any of the subclasses (these can also be mixed):
std::set<Base*> base_set;
base_set.insert(new Sub1);
base_set.insert(new Sub2);
Alternatively, is there a way to create a set that can hold either one
of them?
Take a look at Boost.Any and Boost.Variant. If you have just 2 classes, then variant should suffice. If you plan other types, and don't want to recompile this 'set', then use any.
Then use any container of either any or variant.
#include <boost/any.hpp>
#include <boost/variant.hpp>
#include <vector>
class A { };
class B { };
class C { };
int main()
{
// any
std::vector<boost::any> anies;
anies.push_back(A());
anies.push_back(B());
A a0 = boost::any_cast<A>(anies[0]);
A b0 = boost::any_cast<A>(anies[1]); // throws boost::bad_any_cast
// variant
std::vector<boost::variant<A,B> > vars;
vars.push_back(A());
vars.push_back(B());
A a1 = boost::get<A>(vars[0]);
A b1 = boost::get<A>(vars[1]); // throws boost::bad_get
// and here is the main difference:
anies.push_back(C()); // OK
vars.push_back(C()); // compile error
}
Edit: having more than 2 classes is of course possible for variant, too. But extending variant so it is able to hold a new unanticipated type without recompilation is not.
If a and b are unrelated, then you can use a void* or, better, a boost any type.
If a is superclass of b, you can use an a* instead.
If they both inherit from the same type you can do it. Thats how OOP frameworks work, having all classes inherit from Object.
Although you can do that, what would that pointer mean? If any portion of your application gets hold on the pointer to 'either a or b', it cannot do a lot with it, unless you provide extra type information.
Providing extra type information will result in client code like
if( p->type == 'a' ) {
... a-specific stuff
} else if( p->type == 'b' ) {
... b-specific stuff
} ...
Which isn't very useful.
It would be better to delegate 'type-specificness' to the object itself, which is the nature of object-oriented design, and C++ has a very good type-system for that.
class Interface {
public:
virtual void doClientStuff() = 0; //
virtual ~theInterface(){};
};
class A : public Interface {
virtual void doClientStuff(){ ... a-specific stuff }
};
class B : public Interface {
virtual void doClientStuff(){ ... b-specific stuff }
};
And then your client code will become more type-unaware, since the type-switching is done by C++ for you.
void clientCode( Interface* anObject ) {
anObject->doClientStuff();
}
Interface* i = new A();
Interface* j = new B();
clientCode( i );
clientCOde( j );
There are several ways to do this:
Using the more generic base type, if there is an inheritance relationship.
Using void* and explicitly casting where appropriate.
Creating a wrapper class with the inheritance relationship needed for #1.
Using a discriminating container via union.
Since others have already described the first three options, I will describe the fourth. Basically, a discriminated container uses a union type to use the storage of a single object for storing one of multiple different values. Typically such a union is stored in a struct along with an enum or integral type for distinguishing which value is currently held in the union type. As an example:
// Declarations ...
class FirstType;
class SecondType;
union PointerToFirstOrSecond {
FirstType* firstptr;
SecondType* secondptr;
};
enum FIRST_OR_SECOND_TYPE {
FIRST_TYPE,
SECOND_TYPE
};
struct PointerToFirstOrSecondContainer {
PointerToFirstOrSecond pointer;
FIRST_OR_SECOND_TYPE which;
};
// Example usage...
void OperateOnPointer(PointerToFirstOrSecondContainer container) {
if (container.which == FIRST_TYPE) {
DoSomethingWith(container.pointer.firstptr);
} else {
DoSomethingElseWith(container.pointer.secondptr);
}
}
Note that in the code below, "firstptr" and "secondptr" are actually two different views of the same variable (i.e. the same memory location), because unions share space for their content.
Note that even though this is a possible solution, I seriously wouldn't recommend it. This kind of thing isn't very maintainable. I strongly recommend using inheritance for this if at all possible.
Just define a common superclass C and two subclasses A, B of C. If A and B have no common structure (no common attributes), you can leave C empty.
The define:
A *a = new A();
B *b = new B();
C *c;
Then you can do both
c = a;
or
c = b;
Abstract Class !!!! -- simple solutions
To have a base class that can be used as a pointer to several derived sub classes. (no casting needed)
Abstract class is define when you utilize a virtual method in it. Then you implement this method in the sub-class... simple:
// abstract base class
#include <iostream>
using namespace std;
class Polygon {
protected:
int width, height;
public:
void set_values (int a, int b)
{ width=a; height=b; }
virtual int area (void) =0;
};
class Rectangle: public Polygon {
public:
int area (void)
{ return (width * height); }
};
class Triangle: public Polygon {
public:
int area (void)
{ return (width * height / 2); }
};
int main () {
Polygon * ppoly1 = new Rectangle (4,5);
Polygon * ppoly2 = new Triangle (4,5);
ppoly1->set_values (4,5);
ppoly2->set_values (4,5);
cout << ppoly1->area() << '\n';
cout << ppoly2->area() << '\n';
return 0;
}

Conditional variable declaration

I'm coming from Python and I have some problem with managing types in c++. In Python I can do something like this:
if condition_is_true:
x=A()
else:
x=B()
and in the rest of the program I can use x without caring about the type of x, given that I use methods and member variables with the same name and arguments (not necessary that A and B have the same base classes).
Now in my C++ code type A corresponds to
typedef map<long, C1> TP1;
and B to:
typedef map<long, C2> TP2;
where:
typedef struct C1
{
char* code;
char* descr;
int x;
...
}
and
typedef struct C2
{
char* code;
char* other;
int x;
...
}
C1 and C2 have similar members and in the part of code I'm talkin of I only have to use the ones with the same name/type
I would like to do something like:
if (condition==true)
{
TP1 x;
}
else
{
TP2 x;
}
what is the correct approach in c++?
thanks in advance
If the condition is known at compile-time, you can use std::conditional. This is useful in generic code.
typedef std::conditional<
std::is_pointer<T>::value
, TP1
, TP2
>::type map_type;
map_type x;
(where the test is made-up; here we're testing whether T is a pointer type or not)
If the condition cannot be known until runtime, then some form of dynamic polymorphism is needed. Typical instances of such polymorphism in C++ are subtyping, boost::variant or when push comes to shove, boost::any. Which one you should pick* and how you should apply it depends on your general design; we don't know enough.
*: very likely not to be boost::any.
You have a couple of choices. If C1 and C2 are both POD types, you could use a union, which allows access to the common initial sequence:
struct C1 {
// ....
};
struct C2 {
// ...
};
union TP {
C1 c1;
C2 c2;
};
union TP x;
std::cout << x.c1.code; // doesn't matter if `code` was written via c1 or c2.
Note that to keep the initial sequence "common", you really want to change the names so the second member (descr/other) has the same name in both versions of the struct.
If they're not PODs, you can use inheritance to give you a common type.
C++, however, doesn't have a direct counterpart to Python's famous "duck typing". While templates provide type erasure (to at least some degree), you'd end up with kind of the reverse of what you're doing in Python. Instead of the variation between the two types happening where you deal with the variable, you'd allow code to deal with two different types that had common syntax. This is different, however, in that it requires that the compiler be able to resolve the actual type being used with any particular template at compile time, not just run time.
If you really need to resolve the type at run time, then templates probably won't work -- you'll probably need to use a union or base class.
If you really need two different types, the best thing to do would be (assuming the classes are similar and has some similar member functions) to have an abstract class, say, CBase (see http://www.cplusplus.com/doc/tutorial/polymorphism/) and then define two subclasses C1 and C2 of this abstract class.
Now your code can be written as follows:
CBase *x;
if (condition) {
x = new C1();
} else {
x = new C2();
}
In case you can not abstract C1 and C2 into a common abstract class, well, then you'll need two different variables and condition acts like your flag using which you can know later which variable has been populated and which structure to work with.
Although there may be some ways to do it, they're mostly tricky and not maintainable, just as Damon mentioned.
I recommend you to use template function. What you really want is to access the same member/functions for different class. In template function, you can access the object of a "general type" as long as the type provides the operation you use in the template.
For example, in your case you can simply extract the common parts into a template function like this.
struct TP1
{
// common part
int i;
int j;
// different part
float f;
};
struct TP2
{
// common part
int i;
int j;
// different part
double d;
};
template<typename CType>
void f(CType a)
{
// as long as CType has variable i, j
cout << a.i << endl;
cout << a.j << endl;
}
int main(int argc, char* argv[])
{
bool choice;
// get a choice from console during runtime
cin >> choice;
if (choice)
{
TP1 x = {0, 0};
f(x);
}
else
{
TP2 x = {1, 1};
f(x);
}
return 0;
}
i think you can do it by runtime polymorphism.
class C_Base { /*all common variables*/ } ;
class C1 : public C_Base { ... };
class C2 : public C_Base { ... };
typedef map<long, C_Base *> TP;
{
...
TP x;
if (condition)
/*use x as if values are C1 * */
else
/*other way round*/
}
In order to use two different types through a common variable, the types
must have a common base class. Since what you have is two different
types which you can't change, and which don't have a common base class,
you need some sort of duck typing. In C++, only templates use duck
typing: one solution would be to move all of the code after the
condition into a separate function template, to which you pass the
results, and then write something like:
if ( condition_is_true )
wrapped_code( A() );
else
wrapped_code( B() );
Depending on the code that actually follows the condition, this may be
more or less convenient.
A more general alternative is to create your class hierarchy to wrap the
maps. This solution is a bit verbose, but very easy: just define a base
class with the interface you want, say:
class Map
{
public:
virtual ~Map() {}
virtual std::string getCode( long index ) const = 0;
virtual std::string getDescr( long index ) const = 0;
virtual int getX( long index ) const = 0;
};
, and then a template which derives from it:
template <typename T> // Constraint: T must have accessible members code, other and x
class ConcreteMap : public Map
{
std::map <long, T> myData;
public:
virtual std::string getCode( long index ) const
{
return myData[index].code;
}
virtual std::string getDescr( long index ) const
{
return myData[index].descr;
}
virtual int getX( long index ) const
{
return myData[index].x;
}
};
Your if then becomes:
std::unique_ptr<Map> x = (condition_is_true
? std::unique_ptr<Map>( new ConcreteMap<C1> )
: std::unique_ptr<Map>( new ConcreteMap<C2> ));
What you're trying to do is not possible in C++. Variables in C++ have a fixed type which is defined at compile time and they can't change type at run time. But C++ does provide polymorphism (which looks like dynamic types) which allows derived types to implement base class functionality, but the only way to access type specific methods is to have a type bound to the base class, if you have a type bound to the derived type then you can only call that type's implementation*:
class Base
{
public: virtual void Func () = 0;
};
class C1 : public Base
{
public: virtual void Func () {}
};
class C2 : public Base
{
public: virtual void Func () {}
};
void SomeFunc ()
{
C1 *c1 = new C1;
C2 *c2 = new C2;
Base *b;
b = c1;
b->Func (); // calls C1::Func
b = c2;
b->Func (); // calls C2::Func
}
It looks like b has changed type, but it's actual type has remained the same, it is always a Base * and it can only be assigned the value c1 and c2 because they share a common base class Base. It is possible to go the other way:
Base *b = new C1;
C1 *c1 = dynamic_cast <C1 *> (b);
but it requires the dynamic_cast and that requires something called RTTI (Run-Time Type Information) which provides the compiled code a way to check that b is actually pointing to a C1 type. If you were to do the following:
Base *b = new C2;
C1 *c1 = dynamic_cast <C1 *> (b);
c1 would be the null pointer, not b. But C1 and C2 must still have a common base class for this to work. This is not legal:
class Base {....}
class C1 : public Base {....}
class C2 {....} // not derived from Base!
Base *b = new C2; // no way to convert C2 to Base!
C2 *c2 = new C2;
b = dynamic_cast <Base *> (c2); // still won't work, C2 not a Base
b = new C1; // fine, C1 is a Base
C1 *c1 = new C1;
b = c1; // again, fine
c1 = dynamic_cast <C1 *> (b); // fine, C1 is a derived type of Base, this will work
c2 = dynamic_cast <C2 *> (b); // won't work, C2 is not a derived type of Base
If C1 and C2 are related (say, CSquare and CCircle) then a common base class makes sense. If they are not related (say, CRoad and CFood) then a common base class won't help (it can be done, but it's not very logical). Doing the former (common base class) has been well described in the other answers. If you need to do the latter, then you may need to re-think how the code is structured to allow you to do the former.
It would help if you could expand on what you want to do with x. Since x is a container, do you just want to do container related operations?
Of course, things are never that easy in C++ and there are many things that can confuse the issue. For example, a derived type may implement a public base class virtual method privately:
Example:
class B
{
public:
virtual void F () = 0;
};
class C : public B
{
private:
virtual void F () { .... }
};
C *c = new C;
B *b = c;
b->F (); // OK
c->F (); // error