Conditional variable declaration - c++

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

Related

How to find the largest possible sizeof child class

Given a class, I would like to find the largest sizeof() all child classes of it in compile-time. In this case, you will need to properly define the value of B::BIGGEST_TYPE_SIZE, preferably in the class itself.
It is possible to do so in a separate chunk of code with the usage of std::max() as shown in the last line, but it's some what duplicate code and unelegant, as I will have to continuously modify that line as more classes inherit from B.
I would like a nice scalable solution instead.
struct B
{
static const int BIGGEST_TYPE_SIZE;
};
struct D1 : public B
{
int i;
};
struct D2 : public B
{
std::vector<int> vec;
};
struct D3 : public B
{
std::string s;
};
const int B::BIGGEST_TYPE_SIZE = std::max(sizeof(D1), std::max(sizeof(D2), sizeof(D3)));
The value of BIGGEST_TYPE_SIZE should be "32", due to std::string.
Any elegant solutions for this?
The sexier the templates, the better.
Thanks!
Take for example std::variant, it knows its size from the template arguments. Your best shot is also to use a variadic template. First, you implement the variadic max function template, then you use it:
template <typename ... Ts>
constexpr bool biggest_size_v = max(sizeof(Ts)...);
If you're asking to automatically get a list of all derived classes at compile-time. You can't. You still have to list them:
const int B::BIGGEST_TYPE_SIZE = biggest_size_v<D1, D2, D3>;
It is possible to do so in a separate chunk of code with the usage of std::max as shown in the last line, but it's some what duplicate code and unelegant, as I will have to continuously modify that line as more classes inherit from B.
I would like a nice scalable solution instead.
Unfortunately, I don't know a way to automatically know all derived types (I don't think it's possible) so I fear that you needs "to continuously modify that line as more classes inherit form B".
In LogicStuff's answer you see an elegant way to simplify that line and I also remember that exist the std::max() version that receive a std::initializer_list (constexpr starting from C++14) so you can also write (but the biggest_size_v way is better, IMHO)
const int B::BIGGEST_TYPE_SIZE
= std::max({sizeof(D1), sizeof(D2), sizeof(D3)});
avoiding the multiple std::max() calls.
A little off topic, I suppose, but I propose you a semi-automatic way to check, compile-time, that B::BIGGEST_TYPE_SIZE is bigger (or equal) to the sizeof() of all derived types (all instantiated derived type, at least).
If you modify B adding a constructor with a static_assert() in it (or SFINAE enabled, if you prefer)
struct B
{
static const int BIGGEST_TYPE_SIZE;
template <std::size_t DerSize>
B (std::integral_constant<std::size_t, DerSize>)
{ static_assert( DerSize <= BIGGEST_TYPE_SIZE, "!" ); }
};
and add a template C struct that inherit from B
template <typename Der>
struct C : public B
{
C() : B{std::integral_constant<std::size_t, sizeof(Der)>{}}
{ }
};
if you modify your Dx classes to inheriting B passing through C<Dx> (so using CRTP)
struct D1 : public C<D1>
{ int i; };
struct D2 : public C<D2>
{ std::vector<int> vec; };
struct D3 : public C<D3>
{ std::string s; };
you auto-magically enable the compile-time check inside B constructor.
So if you add, by example, the following D4 class
struct D4 : public C<D4>
{ int a[42]; };
and forget to modify the BIGGEST_TYPE_SIZE initialization adding sizeof(D4) in the list, declaring a D4 object you get a compilation error
D4 d4; // compilation error
The following is a full compiling example
#include <vector>
#include <iostream>
#include <algorithm>
struct B
{
static const int BIGGEST_TYPE_SIZE;
template <std::size_t DerSize>
B (std::integral_constant<std::size_t, DerSize>)
{ static_assert( DerSize <= BIGGEST_TYPE_SIZE, "!" ); }
};
template <typename Der>
struct C : public B
{
C() : B{std::integral_constant<std::size_t, sizeof(Der)>{}}
{ }
};
struct D1 : public C<D1>
{ int i; };
struct D2 : public C<D2>
{ std::vector<int> vec; };
struct D3 : public C<D3>
{ std::string s; };
struct D4 : public C<D4>
{ int a[42]; };
const int B::BIGGEST_TYPE_SIZE
= std::max({sizeof(D1), sizeof(D2), sizeof(D3)}); // <-- sizeof(D4) forgotten !!!
int main ()
{
D1 d1;
D2 d2;
D3 d3;
// D4 d4; compilation error
}

How to « reverse » inheritance when working with polymorphism?

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.

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.

How to search through and assign from a collection of c++ derived objects?

I got a good answer to the technical part of my question as to why my current approach to this is not working (assigning derived** to base** is type-unsafe, see also Converting Derived** to Base** and Derived* to Base*). However, I still don't have a good idea of how to implement what I'm thinking of in a C++ manner. I'm starting a new question, since the last title was too specific.
Here's perhaps a clearer explanation of what I am trying to do:
Create a number of objects which are all instances of classes derived from one single class.
Store these objects in some type of master container along with a compile-time human-readable identifier (probably a string?).
Get a list of identifiers from other components, search through the master container, and pass them back (pointers/references to) the corresponding objects so they can read/modify them. I think I need to break type-safety at this point and assume that the components know the derived type that they are asking for by identifier.
I thought this would be relatively simple and elegant to do with maps, vectors, and pointers to objects (I give a simplified example in my my previous question), but it seems I'm going to have to be doing a lot of C-style type casting to allow the components to pass pointers to the locations to store the value from the master container. This indicates to me that I'm not following a C++ paradigm, but what "should" I do?
[Edit] Here's some hypothetical sample code for how I envisioned this, hope this clarifies my thinking:
#include <map>
#include <vector>
#include <string>
using namespace std;
class BaseObj {};
class Der1Obj: public BaseObj {};
class Der2Obj: public BaseObj {};
typedef map<string, BaseObj**> ObjPtrDict;
typedef map<string, BaseObj*> ObjDict;
class BaseComp
{
public:
ObjPtrDict objs;
};
class DervComp
{
DervComp(){objs["d1"] = &d1; objs["d2"] = &d2; } // This wouldn't compile
Der1Obj* d1;
Der2Obj* d2;
}
typedef vector<BaseComp*> CompList;
void assign_objs(CompList comps, ObjDict objs)
{
for (auto c = comps.begin(); c != comps.end(); c++)
for (auto o = c.objs.begin(); o != c.objs.end(); o++)
*(o->second) = objs[o->first];
}
int main(int argc, char* argv[])
{
Der1Obj d, d1;
Der2Obj d2;
ObjDict objs;
objs["d"] = &d;
objs["d1"] = &d1;
objs["d2"] = &d2;
DervComp c;
vector<DervComp*> comps;
comps.push_back(&c);
assign_objs(comps, objs);
return 0;
}
If I got what you want right, you can do it like this:
#include <vector>
class Base
{
public:
enum eDerived
{
//name these whatever you like
DER1,//for first derived class
DER2,//for second derived class
DER3//for third derived class
};
virtual eDerived type() = 0;//this will return the class type.
};
class Derived1: public Base
{
public:
virtual eDerived type() { return DER1; }
};
class Derived2: public Base
{
public:
virtual eDerived type() { return DER2; }
};
class Derived3: public Base
{
public:
virtual eDerived type() { return DER3; }
};
int main()
{
std::vector<Base*> myList;//container for all elements
//You can store a pointer to any of the derived classes here like this:
Base * a = new Derived1();
Base * b = new Derived2();
Base * c = new Derived3();
myList.push_back(a);
myList.push_back(b);
myList.push_back(c);
//Iterating through the container
for( Base * tmp: myList)
{
//You can check the type of the item like this:
if( tmp->type() == Base::DER1 )
{
//and cast to a corresponding type.
//In this case you are sure that you are casting to the right type, since
//you've already checked it.
Derived1 * pointerToDerived1 = static_cast<Derived1 *>(tmp);
}
}
}
Ofc you can choose any type of container. If you want to give them an ID, you could either use map, or add it into the class itself.
I read your other post, but I think I don´t understand why you would use double pointers. In my understanding you would just use a normal pointer.
E.g.
class Base
{
};
class Deriv : public Base
{
};
std::map< std::string, Base* > ObjectStore;
function Component1( ... )
{
Base* b = ObjectStore[ "MyObject" ];
b->DoSomeFancyStuff();
}
function ModifyObjectStore( )
{
delete ObjectStore[ "MyObject" ];
ObjectStore[ "MyObject" ] = new Derived();
}
I hope this helps.
You says, "pass them back the corresponding object". For this why do you want to pass back the base**? You can simply give back the a map from string to pointer back. Please see the code below for explanation.
class Container
{
void add(const string& aKey_in, Base* b)
{
myObjects[aKey_in] = b;
}
void getObjs(list<string> aKeys_in, map<string,Base*>& anObjMap_out)
{
for(all string s in the aKeys_in)
anObjMap_out[s] = myObjects[s];
}
private:
map<string, base*> myObjects;
};
You conditions meet here:
Create a number of objects which are all instances of classes derived from one single class.
You could extend the class to have creation logic, factory logic etc.
Store these objects in some type of master container along with a compile-time human-readable identifier (probably a string?).
Achieved with the map
Get a list of identifiers from other components, search through the master container, and pass them back (pointers/references to) the corresponding objects so they can read/modify them. I think I need to break type-safety at this point and assume that the components know the derived type that they are asking for by identifier.
You don't need to pass back the pointer to pointer to the client. Just pass back the object pointers.
Additional note:
You could implement the pointers with shared_ptr instead of raw pointers.
If your client code (whoever is using the getObjs() method) is written properly then you won't need a dynamic cast from base pointer to derived pointer. They should be able to work with the base pointer.
Anyway, that is a different question which you haven't asked yet.

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;
}