Achieve polymorphism with contiguous memory - c++

I'm not facing a "problem" actually, as my code does work. I'm just curious about whether my implementations are reasonable and riskless.
I've been working on a project using C++, in which I first parse a file and then build a directed-acyclic-graph structure accordingly. Each nodes may have 0~2 out-neighbors depending on the type of the node. For different types of nodes, some functions for printing and accessing are needed, and I decided to do it using polymorphism.
My first trial was to implement it with nodes storing pointers to its out-neighbors.
class Base{
public:
Base(){}
virtual ~Base(){}
virtual foo()=0;
// ...
protected:
unsigned _index;
}
class Derived1: public Base{
public:
foo(){ /*Do something here...*/ }
private:
Base* _out1;
}
class Derived2: public Base{
public:
foo(){ /*Do something different here...*/ }
private:
Base* _out1;
Base* _out2;
}
int main(){
std::vector<Base*> _nodeList;
for(/*during parsing*/){
if(someCondition){
_nodeList.pushback(new Derived1);
}
// ...
}
}
Since the out-neighbor of a node may be yet to define when the node is constructed, I have to add some tricks to first remember id of the out-neighbors and connect them after finishing the construction of all nodes.
However, since the number of nodes are determined given the file to parse and will not grow ever after, I consider it better to store all nodes contiguously and each node store the indices of its out-neighbors instead of pointers. This allows me to skip the connection part and also brings some minor benefits to other parts.
My current version is as follows:
// Something like this
class Base{
public:
Base(){}
virtual ~Base(){}
virtual foo()=0;
// ...
protected:
unsigned _index;
unsigned _out1;
unsigned _out2;
}
class Derived1: public Base{
public:
foo(){ /*Do something here...*/ }
}
class Derived2: public Base{
public:
foo(){ /*Do something a little bit different here...*/ }
}
int main(){
// EDITED!!
// Base* _nodeList = new DefaultNode[max_num];
Base* _nodeList = new Derived2[max_num];
for(/*during parsing*/){
if(someCondition){
// EDITED!!
// _nodeList[i] = Derived1;
new(_nodeList+i) Derived1();
}
// ...
}
}
My questions
Are there any risks to store objects of different class in a newed array, given that they are all of the same size and can be destructed using a virtual destructor?
I've always heard that the use of new[] should be avoided. I did found some approaches that achieve what I want using vector of union with a type tag, but it seems somewhat dirty to me. Is there a way to achieve polymorphism while storing data in a std::vector?
Is the practice of using polymorphism merely to make use of the convenience of virtual functions consider a bad habit? By saying so I mean if the memory taken by each object is already the same for each derived class, then they may be merged into one single class that store its own type, and each member function can just behave according to its own type. I chose not to do so since it also looks dirty to me to have huge switch structure in each member function.
Is it good to choose contiguous memory in this case? Are there any reasons that such choice may be harmful?
EDIT:
It turns out that I'm making many mistakes such as asking too many questions at a time. I think I'll first focus on the part with polymorphism and placement new. The following is a testable program of what I mean by "storing objects of different derived classes in an newed array, and it behaves on my laptop as shown below.
#include <iostream>
class Base{
public:
Base(){}
virtual ~Base(){}
void virtual printType() =0;
};
class Derived1: public Base{
public:
Derived1(){}
void printType(){ std::cout << "Derived 1." << std::endl; }
};
class Derived2: public Base{
public:
Derived2(){}
void printType(){ std::cout << "Derived 2." << std::endl; }
};
int main(){
Base* p = new Derived1[5];
new(p+2) Derived2();
for(unsigned i = 0; i < 5; ++i){
(p+i)->printType();
}
}
Outcome:
Derived 1.
Derived 1.
Derived 2.
Derived 1.
Derived 1.
Again, thanks for all the feedbacks and suggestions.

Are there any risks to store objects of different class in an newed array, given that they are all of the same size and can be destructed
using a virtual destructor?
This is not what happens in your second proposition:
Base* _nodeList = new DefaultNode[max_num];
_nodeList is an array of DefaultNote and nothing else! Trying to store something in it like _nodeList[i] = ... will never change anything about the nature of stored objects (note that _nodeList[i] = Derived1; is not C++). If you want polymorphism you need to retain objects either through pointers or references. Then the first solution is the correct one: std::vector<Base*> _nodeList;.
I've always heard that the use of new[] should be avoided. I did found some approaches that achieve what I want using vector of union
with a type tag, but it seems somewhat dirty to me. Is there a way to
achieve polymorphism while storing data in a std::vector?
the use of new[] should be avoided is a non-sense. As said before, if you need polymorphism then std::vector<Base*> _nodeList; is perfect, because that means that you can store in _nodeList the address of any object whose class is either Base or any subtype of.
Is the practice of using polymorphism merely to make use of the
convenience of virtual functions consider a bad habit? By saying so I
mean if the memory taken by each object is already the same for each
derived class, then they may be merged into one single class that
store its own type, and each member function can just behave according
to its own type. I chose not to do so since it also looks dirty to me
to have huge switch structure in each member function.
Subtyped polymorphism is the use of virtual functions. Why bad habit? If you don't use virtual functions that just means that you are constructing the polymorphism by yourself, which is probably a very bad thing.
Now, if your derived classes are just like what was proposed in your exemple, I can suggested you not to use subclasses but only ctor overloading...
Is it good to choose contiguous memory in this case? Are there any reasons that such choice may be harmful?
I'm not sure to really understand why this is a concern for you. Contiguous memory is not harmful... This question is at least not clear.

The problem is that normally you cannot allocate different polymorphic classes inside a vector or array - only pointers to them. So you cannot make it contiguous.
In your case usage of polymorphism is most probably a bad idea. It will result in poor memory fragmentation and slow performance due to issues with lots of virtual calls and fails on the branch prediction. Though, if there aren't many nodes or you don't use it too frequently in your code - then it won't affect the overall performance of the program.
To avoid this, simply store nodes' data (and make it a plain struct) inside a vector and utilize separate classes that implement those foo() functions.
Example:
std::vector<NodeData> nodes;
class Method1
{
public:
static void Process(NodeData& node);
...
}
class Method2
{
public:
static void Process(NodeData& node);
...
}
Then you can either make a single switch to choose which method to apply or, say, store nodes' data inside several vectors so that each vector identifies which method to use.

Related

Defining a class with an vector of interfaces [duplicate]

Having spent quite some time developping in C#, I noticed that if you declare an abstract class for the purpose of using it as an interface you cannot instantiate a vector of this abstract class to store instances of the children classes.
#pragma once
#include <iostream>
#include <vector>
using namespace std;
class IFunnyInterface
{
public:
virtual void IamFunny() = 0;
};
class FunnyImpl: IFunnyInterface
{
public:
virtual void IamFunny()
{
cout << "<INSERT JOKE HERE>";
}
};
class FunnyContainer
{
private:
std::vector <IFunnyInterface> funnyItems;
};
The line declaring the vector of abstract class causes this error in MS VS2005:
error C2259: 'IFunnyInterface' : cannot instantiate abstract class
I see an obvious workaround, which is to replace IFunnyInterface with the following:
class IFunnyInterface
{
public:
virtual void IamFunny()
{
throw new std::exception("not implemented");
}
};
Is this an acceptable workaround C++ wise ?
If not, is there any third party library like boost which could help me to get around this ?
Thank you for reading this !
Anthony
You can't instantiate abstract classes, thus a vector of abstract classes can't work.
You can however use a vector of pointers to abstract classes:
std::vector<IFunnyInterface*> ifVec;
This also allows you to actually use polymorphic behaviour - even if the class wasn't abstract, storing by value would lead to the problem of object slicing.
You can't create a vector of an abstract class type because you cannot create instances of an abstract class, and C++ Standard Library containers like std::vector store values (i.e. instances). If you want to do this, you will have to create a vector of pointers to the abstract class type.
Your workround would not work because virtual functions (which is why you want the abstract class in the first place) only work when called through pointers or references. You cannot create vectors of references either, so this is a second reason why you must use a vector of pointers.
You should realise that C++ and C# have very little in common. If you are intending to learn C++, you should think of it as starting from scratch, and read a good dedicated C++ tutorial such as Accelerated C++ by Koenig and Moo.
In this case we can't use even this code:
std::vector <IFunnyInterface*> funnyItems;
or
std::vector <std::tr1::shared_ptr<IFunnyInterface> > funnyItems;
Because there is no IS A relationship between FunnyImpl and IFunnyInterface and there is no implicit convertion between FUnnyImpl and IFunnyInterface because of private inheritance.
You should update your code as follows:
class IFunnyInterface
{
public:
virtual void IamFunny() = 0;
};
class FunnyImpl: public IFunnyInterface
{
public:
virtual void IamFunny()
{
cout << "<INSERT JOKE HERE>";
}
};
The traditional alternative is to use a vector of pointers, like already noted.
For those who appreciate, Boost comes with a very interesting library: Pointer Containers which is perfectly suited for the task and frees you from the various problems implied by pointers:
lifetime management
double dereferencing of iterators
Note that this is significantly better than a vector of smart pointers, both in terms of performance and interface.
Now, there is a 3rd alternative, which is to change your hierarchy. For better insulation of the user, I have seen a number of times the following pattern used:
class IClass;
class MyClass
{
public:
typedef enum { Var1, Var2 } Type;
explicit MyClass(Type type);
int foo();
int bar();
private:
IClass* m_impl;
};
struct IClass
{
virtual ~IClass();
virtual int foo();
virtual int bar();
};
class MyClass1: public IClass { .. };
class MyClass2: public IClass { .. };
This is quite straightforward, and a variation of the Pimpl idiom enriched by a Strategy pattern.
It works, of course, only in the case where you do not wish to manipulate the "true" objects directly, and involves deep-copy. So it may not be what you wish.
Because to resize a vector you need to use the default constructor and the size of the class, which in turn requires it to be concrete.
You can use a pointer as other suggested.
std::vector will try to allocate memory to contain your type. If your class is purely virtual, the vector cannot know the size of the class it will have to allocate.
I think that with your workaround, you will be able to compile a vector<IFunnyInterface> but you won't be able to manipulate FunnyImpl inside of it. For example if IFunnyInterface (abstract class) is of size 20 (i dont really know) and FunnyImpl is of size 30 because it has more members and code, you will end up trying to fit 30 into your vector of 20
The solution would be to allocate memory on the heap with "new" and store pointers in vector<IFunnyInterface*>
I think that the root cause of this really sad limitation is the fact that constructors can not virtual. Thereof compiler can not generate code which copy the object without knowing its time in the compile time.

How to include base class without implementing pure virtual functions? [duplicate]

Having spent quite some time developping in C#, I noticed that if you declare an abstract class for the purpose of using it as an interface you cannot instantiate a vector of this abstract class to store instances of the children classes.
#pragma once
#include <iostream>
#include <vector>
using namespace std;
class IFunnyInterface
{
public:
virtual void IamFunny() = 0;
};
class FunnyImpl: IFunnyInterface
{
public:
virtual void IamFunny()
{
cout << "<INSERT JOKE HERE>";
}
};
class FunnyContainer
{
private:
std::vector <IFunnyInterface> funnyItems;
};
The line declaring the vector of abstract class causes this error in MS VS2005:
error C2259: 'IFunnyInterface' : cannot instantiate abstract class
I see an obvious workaround, which is to replace IFunnyInterface with the following:
class IFunnyInterface
{
public:
virtual void IamFunny()
{
throw new std::exception("not implemented");
}
};
Is this an acceptable workaround C++ wise ?
If not, is there any third party library like boost which could help me to get around this ?
Thank you for reading this !
Anthony
You can't instantiate abstract classes, thus a vector of abstract classes can't work.
You can however use a vector of pointers to abstract classes:
std::vector<IFunnyInterface*> ifVec;
This also allows you to actually use polymorphic behaviour - even if the class wasn't abstract, storing by value would lead to the problem of object slicing.
You can't create a vector of an abstract class type because you cannot create instances of an abstract class, and C++ Standard Library containers like std::vector store values (i.e. instances). If you want to do this, you will have to create a vector of pointers to the abstract class type.
Your workround would not work because virtual functions (which is why you want the abstract class in the first place) only work when called through pointers or references. You cannot create vectors of references either, so this is a second reason why you must use a vector of pointers.
You should realise that C++ and C# have very little in common. If you are intending to learn C++, you should think of it as starting from scratch, and read a good dedicated C++ tutorial such as Accelerated C++ by Koenig and Moo.
In this case we can't use even this code:
std::vector <IFunnyInterface*> funnyItems;
or
std::vector <std::tr1::shared_ptr<IFunnyInterface> > funnyItems;
Because there is no IS A relationship between FunnyImpl and IFunnyInterface and there is no implicit convertion between FUnnyImpl and IFunnyInterface because of private inheritance.
You should update your code as follows:
class IFunnyInterface
{
public:
virtual void IamFunny() = 0;
};
class FunnyImpl: public IFunnyInterface
{
public:
virtual void IamFunny()
{
cout << "<INSERT JOKE HERE>";
}
};
The traditional alternative is to use a vector of pointers, like already noted.
For those who appreciate, Boost comes with a very interesting library: Pointer Containers which is perfectly suited for the task and frees you from the various problems implied by pointers:
lifetime management
double dereferencing of iterators
Note that this is significantly better than a vector of smart pointers, both in terms of performance and interface.
Now, there is a 3rd alternative, which is to change your hierarchy. For better insulation of the user, I have seen a number of times the following pattern used:
class IClass;
class MyClass
{
public:
typedef enum { Var1, Var2 } Type;
explicit MyClass(Type type);
int foo();
int bar();
private:
IClass* m_impl;
};
struct IClass
{
virtual ~IClass();
virtual int foo();
virtual int bar();
};
class MyClass1: public IClass { .. };
class MyClass2: public IClass { .. };
This is quite straightforward, and a variation of the Pimpl idiom enriched by a Strategy pattern.
It works, of course, only in the case where you do not wish to manipulate the "true" objects directly, and involves deep-copy. So it may not be what you wish.
Because to resize a vector you need to use the default constructor and the size of the class, which in turn requires it to be concrete.
You can use a pointer as other suggested.
std::vector will try to allocate memory to contain your type. If your class is purely virtual, the vector cannot know the size of the class it will have to allocate.
I think that with your workaround, you will be able to compile a vector<IFunnyInterface> but you won't be able to manipulate FunnyImpl inside of it. For example if IFunnyInterface (abstract class) is of size 20 (i dont really know) and FunnyImpl is of size 30 because it has more members and code, you will end up trying to fit 30 into your vector of 20
The solution would be to allocate memory on the heap with "new" and store pointers in vector<IFunnyInterface*>
I think that the root cause of this really sad limitation is the fact that constructors can not virtual. Thereof compiler can not generate code which copy the object without knowing its time in the compile time.

Ranged based for loop not compiling with vector of abstract class [duplicate]

Having spent quite some time developping in C#, I noticed that if you declare an abstract class for the purpose of using it as an interface you cannot instantiate a vector of this abstract class to store instances of the children classes.
#pragma once
#include <iostream>
#include <vector>
using namespace std;
class IFunnyInterface
{
public:
virtual void IamFunny() = 0;
};
class FunnyImpl: IFunnyInterface
{
public:
virtual void IamFunny()
{
cout << "<INSERT JOKE HERE>";
}
};
class FunnyContainer
{
private:
std::vector <IFunnyInterface> funnyItems;
};
The line declaring the vector of abstract class causes this error in MS VS2005:
error C2259: 'IFunnyInterface' : cannot instantiate abstract class
I see an obvious workaround, which is to replace IFunnyInterface with the following:
class IFunnyInterface
{
public:
virtual void IamFunny()
{
throw new std::exception("not implemented");
}
};
Is this an acceptable workaround C++ wise ?
If not, is there any third party library like boost which could help me to get around this ?
Thank you for reading this !
Anthony
You can't instantiate abstract classes, thus a vector of abstract classes can't work.
You can however use a vector of pointers to abstract classes:
std::vector<IFunnyInterface*> ifVec;
This also allows you to actually use polymorphic behaviour - even if the class wasn't abstract, storing by value would lead to the problem of object slicing.
You can't create a vector of an abstract class type because you cannot create instances of an abstract class, and C++ Standard Library containers like std::vector store values (i.e. instances). If you want to do this, you will have to create a vector of pointers to the abstract class type.
Your workround would not work because virtual functions (which is why you want the abstract class in the first place) only work when called through pointers or references. You cannot create vectors of references either, so this is a second reason why you must use a vector of pointers.
You should realise that C++ and C# have very little in common. If you are intending to learn C++, you should think of it as starting from scratch, and read a good dedicated C++ tutorial such as Accelerated C++ by Koenig and Moo.
In this case we can't use even this code:
std::vector <IFunnyInterface*> funnyItems;
or
std::vector <std::tr1::shared_ptr<IFunnyInterface> > funnyItems;
Because there is no IS A relationship between FunnyImpl and IFunnyInterface and there is no implicit convertion between FUnnyImpl and IFunnyInterface because of private inheritance.
You should update your code as follows:
class IFunnyInterface
{
public:
virtual void IamFunny() = 0;
};
class FunnyImpl: public IFunnyInterface
{
public:
virtual void IamFunny()
{
cout << "<INSERT JOKE HERE>";
}
};
The traditional alternative is to use a vector of pointers, like already noted.
For those who appreciate, Boost comes with a very interesting library: Pointer Containers which is perfectly suited for the task and frees you from the various problems implied by pointers:
lifetime management
double dereferencing of iterators
Note that this is significantly better than a vector of smart pointers, both in terms of performance and interface.
Now, there is a 3rd alternative, which is to change your hierarchy. For better insulation of the user, I have seen a number of times the following pattern used:
class IClass;
class MyClass
{
public:
typedef enum { Var1, Var2 } Type;
explicit MyClass(Type type);
int foo();
int bar();
private:
IClass* m_impl;
};
struct IClass
{
virtual ~IClass();
virtual int foo();
virtual int bar();
};
class MyClass1: public IClass { .. };
class MyClass2: public IClass { .. };
This is quite straightforward, and a variation of the Pimpl idiom enriched by a Strategy pattern.
It works, of course, only in the case where you do not wish to manipulate the "true" objects directly, and involves deep-copy. So it may not be what you wish.
Because to resize a vector you need to use the default constructor and the size of the class, which in turn requires it to be concrete.
You can use a pointer as other suggested.
std::vector will try to allocate memory to contain your type. If your class is purely virtual, the vector cannot know the size of the class it will have to allocate.
I think that with your workaround, you will be able to compile a vector<IFunnyInterface> but you won't be able to manipulate FunnyImpl inside of it. For example if IFunnyInterface (abstract class) is of size 20 (i dont really know) and FunnyImpl is of size 30 because it has more members and code, you will end up trying to fit 30 into your vector of 20
The solution would be to allocate memory on the heap with "new" and store pointers in vector<IFunnyInterface*>
I think that the root cause of this really sad limitation is the fact that constructors can not virtual. Thereof compiler can not generate code which copy the object without knowing its time in the compile time.

Is it ever a good idea to put virtual methods on a copyable type?

Have seen some related questions, but not this exact one...
I've treated classes as fitting into a few major categories, let's say these four for simplicity:
Value Classes which have some data and a bunch of operations. They can be copied and meaningfully compared for equality (with copies expected to be equal via ==). These pretty much always lack virtual methods.
Unique Classes whose instances have identity that you disable assignment and copying on. There's usually not an operator== on these because you compare them as pointers, not as objects. These quite often have a lot of virtual methods, as there isn't risk of object-slicing since you're being forced to pass them by pointer or reference.
Unique-but-Clonable Classes which disable copying, but are pre-designed to support cloning if that's what you really want. These have virtual methods, most importantly those following the virtual construction / cloning idiom
Container Classes which inherit the properties of whatever they're holding. These tend not to have virtual methods...see for instance "Why don't STL containers have virtual destructors?".
Regardless of holding this informal belief system, a couple times I've tried adding a virtual method to something copyable. While I may have thought it would "be really cool if that worked", inevitably it breaks.
This led me to wonder if anyone has an actual good example of a type which has virtual methods and doesn't disable copying?
The only counter-example that I have are classes that are meant to be stack-allocated and not heap-allocated. One scheme I use it for is Dependency Injection:
class LoggerInterface { public: virtual void log() = 0; };
class FileLogger final: public LoggerInterface { ... };
int main() {
FileLogger logger("log.txt");
callMethod(logger, ...);
}
The key point here is the final keyword though, it means that copying a FileLogger cannot lead to object-slicing.
However, it might just be that being final turned FileLogger into a Value class.
Note: I know, copying a logger seems weird...
There's nothing inherently wrong in being able to copy a polymorphic class. The problem is being able to copy a non-leaf class. Object slicing will get you.
A good rule of thumb to follow is never derive from a concrete class. This way, non-leaf classes are automatically non-instantiable and thus non-copyable. It won't hurt to disable assignment in them though, just to be on the safe side.
Of course nothing is wrong with copying an object via a virtual function. This kind of copying is safe.
Polymorphic classes are normally not "value-classes" but it does happen. std::stringstream comes to mind. It'not copyable, but it is movable (in C++11) and moving is no different from copying with regard to slicing.
Virtual dispatch happens a runtime. The only reason one should want it is when the actual, dynamic type of an object cannot be known until runtime. If you already knew the desired dynamic type when writing the program, you could use different, non-virtual techniques (such as templates, or non-polymorphic inheritance) to structure your code.
A good example for the need for runtime typing is parsing I/O messages, or handling events – any kind of situation where one way or another you'll either have some sort of big switch table to pick the correct concrete type, or you write your own registration-and-dispatch system, which basically reinvents polymorphism, or you just use virtual dispatch.
(Let me interject a warning: Many people misuse virtual functions to solve problems that don't need them, because they're not dynamic. Beware, and be critical of what you see.)
With this said, it's now clear that your code will be dealing mostly with the polymorphic base classes, e.g. in function interfaces or in containers. So let's rephrase the question: Should such a base class be copyable? Well, since you never have actual, most-derived base objects (i.e. the base class is essentially abstract), this isn't really an issue, and there's no need for this. You've already mentioned the "clone" idiom, which is the appropriate analogue of copying in a polymorphic.
Now, the "clone" function is necessarily implemented in every leaf class, and it necessarily requires copying of the leaf classes. So yes, every leaf class in a clonable hierarchy is a class with virtual functions and a copy constructor. And since the copy constructor of a derived class needs to copy its base subobjects, all the bases need to be copyable, too.
So, now I believe we've distilled the problem down to two possible cases: Either everything in your class hierarchy is completely uncopyable, or your hierarchy supports cloning, and thus by necessity every class in it is copyable.
So should a class with virtual functions have a copy constructor? Absolutely. (This answers your original question: when you integrate your class into a clonable, polymorphic hierarchy, you add virtual functions to it.)
Should you try to make a copy from a base reference? Probably not.
Not with a single, but with two classes:
#include <iostream>
#include <vector>
#include <stdexcept>
class Polymorph
{
protected:
class Implementation {
public:
virtual ~Implementation() {};
// Postcondition: The result is allocated with new.
// This base class throws std::logic error.
virtual Implementation* duplicate() {
throw std::logic_error("Duplication not supported.");
}
public:
virtual const char* name() = 0;
};
// Precondition: self is allocated with new.
Polymorph(Implementation* self)
: m_self(self)
{}
public:
Polymorph(const Polymorph& other)
: m_self(other.m_self->duplicate())
{}
~Polymorph() {
delete m_self;
}
Polymorph& operator = (Polymorph other) {
swap(other);
return *this;
}
void swap(Polymorph& other) {
std::swap(m_self, other.m_self);
}
const char* name() { return m_self->name(); }
private:
Implementation* m_self;
};
class A : public Polymorph
{
protected:
class Implementation : public Polymorph::Implementation
{
protected:
Implementation* duplicate() {
return new Implementation(*this);
}
public:
const char* name() { return "A"; }
};
public:
A()
: Polymorph(new Implementation())
{}
};
class B : public Polymorph {
protected:
class Implementation : public Polymorph::Implementation {
protected:
Implementation* duplicate() {
return new Implementation(*this);
}
public:
const char* name() { return "B"; }
};
public:
B()
: Polymorph(new Implementation())
{}
};
int main() {
std::vector<Polymorph> data;
data.push_back(A());
data.push_back(B());
for(auto x: data)
std::cout << x.name() << std::endl;
return 0;
}
Note: In this example the objects are copied, always (you may implement shared semantics, though)

Is this a design flaw?

Consider two classes
class A{
public:
A(){
}
~A(){
}
};
class AImpl : public A{
public:
AImpl(){
a = new AInternal();
}
AImpl(AInternal *a){
this->_a = a;
}
~AImpl(){
if(a){
delete a;
a = null;
}
}
private:
AInternal *a;
};
I am trying to hide the AInternal's implementation and expose only A's interface. Two things I see here
class A is totally empty.
Hiding is achieved basically through inheritance. I have to actually use downcasting and upcasting from A to AImpl and vice versa.
Is this a good design. Being very inexperienced in designing, I cannot see the pitfalls of it and why it is bad?
You're overcomplicating things by using 3 classes. I think what you're looking for is the pimpl idiom.
I am trying to hide the AInternal's implementation and expose only A's interface.
I think you are trying to do something like factory.
Here is an example:
class IA {
public:
IA() {}
virtual ~IA() {}
virtual void dosth() =0;
};
class Factory {
private:
class A : public IA {
public:
A () {}
virtual ~A() {}
void dosth() { cout << "Hello World"; }
};
public:
Factory () {}
virtual ~Factory() {}
IA*newA() { return new A; }
};
And the usage of Factory class:
Factory f;
IA*a = f.newA();
a->dosth();
return 0;
IMO AInternal makes no sense. Whatever you do there, should be done in AImpl. Otherwise, it's ok to do that in C++.
The code is rather obtuse, so I would be concerned with maintaining it six months down the road.
If you're going to do it this way, then the destructor ~A needs to be virtual.
You seem to be combining two common design features:
1) AInternal is a "pimpl". It provides for better encapsulation, for example if you need to add a new field to AInternal, then the size of AImpl doesn't change. That's fine.
2) A is an base class used to indicate an interface. Since you talk about upcasting and downcasting, I assume you want dynamic polymorphism, meaning that you'll have functions which pass around pointers or references to A, and at runtime the referands will actually be of type AImpl. That's also fine, except that A's destructor should either be virtual and public, or non-virtual and protected.
I see no other design problems with this code. Of course you'll need to actually define the interface A, by adding some pure virtual member functions to it that you implemented in AImpl. Assuming you plan to do that, there's nothing wrong with using an empty base class for the purpose which in Java is served by interfaces (if you know Java). Generally you'd have some kind of factory which creates AImpl objects, and returns them by pointer or reference to A (hence, upcasts them). If the client code is going to create AImpl objects directly then that might also be fine, and in fact you might not need dynamic polymorphism at all. You could instead get into templates.
What I don't see is why you would ever have to downcast (that is, cast an A* to AImpl*). That's usually bad news. So there may be some problems in your design which can only be revealed by showing us more of the definitions of the classes, and the client code which actually uses A and AImpl.