Hi
I've started working on some pre-existing code which consists of a tree of elements, each element is a descendant of a generic element which has a type data member.
The search functionality returns a generic element, the user then checks the type and can downcast to the specific type to access its specific information.
This code is for a mobile handset so using lots of dynamic_casts might be inefficient.
The code is new and not set in stone and so can be improved (I didn't write it, I've just joined the company and am working on it so don't want to rip it apart completely).
What are some options for a good design/use pattern going forward? (Its c++ but using type-checking and raw c casting (to avoid overheads of dynamic_casts) seems a bit old fashioned).
Is there any advantage in adding CastToXXX() type functions in the base class for example?
The types of derived classes will most likely be fixed.
dynamic_cast is not that slow, and you're likely not going to be able to do better. Profile and prove that it is a performance bottleneck before looking at alternative solutions. Never ever do anything because you maybe heard somewhere that it might be slow.
If dynamic_cast/RTTI is not an option, an easy way of dealing with this type of situation is by use of the Visitor Pattern
Basically, you define a base class that defines methods that do the casting for you safely:
// Forward declarations.
class CFoo;
class CBar;
class CommonBase
{
public:
virtual CFoo* GetFoo( void ) { return NULL };
virtual CBar* GetBar( void ) { return NULL };
};
class CFoo : public GenericBase, public CommonBase
{
.
.
public:
CFoo* GetFoo( void ) { return this };
};
class CBar : public GenericBase, public CommonBase
{
.
.
public:
CBar * GetBar( void ) { return this };
};
Now, given a pointer to a CommonBase object one can downcast by "visting":
CommonBase *p;
CFoo pFoo = p->GetFoo();
if( pFoo )
{
// Winner!
}
Let the base class in the tree structure have a pure virtual Visit() method.
class CBase {
virtual void Visit(CVisitor* visitor) const = 0;
};
Let the inherited classes implement it:
class CFoo : public CBase {
virtual void Visit(CVisitor* visitor) const {
visitor->Accept(this);
}
};
class CBar : public CBase {
virtual void Visit(CVisitor* visitor) const {
visitor->Accept(this);
}
};
The final magic:
class CVisitor {
void Accept(CFoo* foo) {
// operate on CFoo*
}
void Accept(CBar* bar) {
// operate on CBar*
}
};
So all you need to do is to create Accept and Visit methods for new types and traverse the tree with the CVisitor class and then you can operate on any type in the tree without any pointer casts.
Hope this helps.
Cheers
Related
I have the following class structure for Managing callbacks with different prototypes:
class MethodHandlerBase: public std::enable_shared_from_this<MethodHandlerBase>{
public:
virtual void operator()(void* data) = 0;
virtual ~MethodHandlerBase(){}
};
class MethodHandlerA: public MethodHandlerBase{
private:
MethodHandlerACallback cb;
public:
MethodHandlerA(MethodHandlerACallback cb): cb(cb){}
virtual void operator()(void* data);
};
class MethodHandlerB: public MethodHandlerBase{
private:
MethodHandlerBCallback cb;
public:
MethodHandlerB(MethodHandlerBCallback cb): cb(cb){}
virtual void operator()(void* data);
};
In some cases MethodHandlerA or MethodHandlerB might use this (wrapped in a shared_ptr) in a lambda expression passed to elsewhere, so I need to be sure that it is correctly deleted when needed. Therefore I added the std::enable_shared_from_this<MethodHandlerBase> inheritance to the base class.
But I read that you usally cannot use std::enable_shared_from_this via inheritance (apart from using a template, which actually would not really be inheritance anymore). In my understanding this is due to the possible wrongly destruction of the instance. In this case I would assume my code would work properly since it uses a virtual destructor (which is needed anyway).
So am I right with my theory or is there something else going on about std::enable_shared_from_this inheritance that I did not understand?
EDIT:
To add a short examples of what I plan to use it like:
From inside the class:
void MethodHandlerB::operator()(void* data){
std::shared_ptr<MethodHandlerB> thisPtr = std::dynamic_pointer_cast<MethodHandlerB>(this->shared_from_this());
putLamdaToSomeGlobalEventThing([thisPtr](){
thisPtr->doSomething();
});
}
and from outside
std::vector<MethodHandlerBase> vec{std::make_shared<MethodHandlerB>()};
Some minor points:
You could move the shared pointer into the lambda to avoid an atomic increment and decrement
No need to use a dynamic pointer cast since you know for sure the dynamic type (plus you don't check the result is not empty anyway!)
void MethodHandlerB::operator()(void* data){
auto thisPtr = std::static_pointer_cast<MethodHandlerB>(this->shared_from_this());
putLamdaToSomeGlobalEventThing([thisPtr = std::move(thisPtr)](){
thisPtr->doSomething();
});
}
Alternatively, you could use separate captures for this and the shared pointer, which avoids the cast altogether:
void MethodHandlerB::operator()(void* data){
putLamdaToSomeGlobalEventThing([this, thisPtr = shared_from_this()](){
doSomething();
});
}
Edit: as one of the comments points out, if you don't use shared_from_this() directly on the base class, you're better off just deriving from enable_shared_from_this in the derived classes. You can do this because C++ supports multiple inheritence.
class MethodHandlerBase {
public:
virtual void operator()(void* data) = 0;
virtual ~MethodHandlerBase(){}
};
class MethodHandlerA:
public MethodHandlerBase,
public std::enable_shared_from_this<MethodHandlerA>
{
private:
MethodHandlerACallback cb;
public:
MethodHandlerA(MethodHandlerACallback cb): cb(cb){}
virtual void operator()(void* data);
};
void MethodHandlerA::operator()(void* data){
putLamdaToSomeGlobalEventThing([self = shared_from_this()](){
self->doSomething();
});
}
You can make a little helper class
template <class Base, class Derived>
struct enable_shared : public Base
{
std::shared_ptr<Derived> shared_from_this()
{
return std::static_pointer_cast<Derived>(
Base::shared_from_this());
};
};
Now you can use shared_from_this freely in all these classes. and it will return the correct type:
class Base : public std::enable_shared_from_this<Base> ...;
class Derived : public enable_shared<Base, Derived> ...;
class MoreDerived : public enable_shared<Derived, MoreDerived> ...;
By the way, if you use std::make_shared, then a virtual destructor is not needed, because the shared pointer is created with the right deleter for the most derive type. It is probably a good idea to define one anyway, just to be on the safe size. (Or maybe not.)
I want to know the type of my class at compilation and i want to know if my idea is considered bad programming or if its actually viable. May correct me if there is a better way to realize this.
class Base {
int type = 0;
}
class Derivative : public Base{
Derivative(){
type = 1;
SomeObject1 o;
SomeAnotherObject o1;
}
}
class Derivative2 : public Base{
Derivative2(){
type = 2;
RandomObject test;
AnotherObject v;
}
}
Some method that gets myBaseClass as Base:
if(myBaseClass.type == 1){
Derivative d = static_cast<Derivative>(myBaseClass);
d.o;
d.o1;
}
if(myBaseClass.type == 2){
Derivative2 d = static_cast<Derivative2>(myBaseClass);
d.test;
d.v;
}
In my opinion it would be unusual to write virtual methods for all different Objects
Is saving the type in the base class considered bad programming
Definitely, yes!
Using a polymorphic virtual design you don't need to have that extra information stored into the base class. The compiler already does that for you:
class Base {
protected:
virtual ~Base() {} // <<<<<<<<<<<<<
}; // Note the ;!
class Derivative : public Base{
};
class Derivative2 : public Base{
};
You can always detect the real class type from a Base pointer or reference with a dynamic_cast then:
Base* pd1 = new Derivative();
Base* pd2 = new Derivative2();
if(dynamic_cast<Derivative>(pd1)) { // Yields true
}
if(dynamic_cast<Derivative>(pd2)) { // Yields false
}
Though if you need to know that, that's a serious indicator of a bad design.
You should rather introduce some interfaces in form of pure virtual function definitions:
class Base {
protected:
virtual ~Base() {}
public:
virtual void DoSomething() = 0;
};
class Derivative : public Base{
public:
void DoSomething() override {
// provide an implementation specific for Derivative
}
};
class Derivative2 : public Base{
public:
void DoSomething() override {
// provide an implementation specific for Derivative2
}
};
That allows you to call DoSomething() without knowing the specific type that implements that function:
Base* pd1 = new Derivative();
Base* pd2 = new Derivative2();
pd1->DoSomething(); // calls Derivative specific implementation
pd2->DoSomething(); // calls Derivative2 specific implementation
To make safe and efficient use of the static_cast use the CRTP instead:
template<typename Derived>
class Base {
public:
void DoSomething() {
static_cast<Derived*>(this)->DoSomething();
}
};
class Derivative : public Base<Derivative> {
};
class Derivative2 : public Base<Derivative2> {
};
Here's the (ugly) approach I used a few years back when hacking-together a pdf writer. It appears to solve exactly the same problem that you have.
pdfArray::pdfArray(const pdfArray &src)
{
vecObjPtrIter iter;
pdfObj *ptr;
mArray = new vecObjPtr;
for (iter=src.mArray->begin(); iter!=src.mArray->end(); iter++)
{
ptr = *iter;
if (typeid(*ptr) == typeid(pdfString))
addItem( (pdfString*)ptr );
if (typeid(*ptr) == typeid(pdfInt))
addItem( (pdfInt*)ptr );
if (typeid(*ptr) == typeid(pdfFloat))
addItem( (pdfFloat*)ptr );
if (typeid(*ptr) == typeid(pdfArray))
addItem( (pdfArray*)ptr );
}
}
There are uses of this technique that are at least plausible. One that I've seen involved a class hierarchy whose instances needed to be configured by the user (driven from Python) and then used in performance-critical code (in C++). The base class provided a getType() method that returned an enumeration; the wrapper code in Python called this to discover which interface to offer the user. Cross-language code often forces the use of simple-minded techniques like this based on agreed-upon integer labels.
More generally, sometimes good design principles like MVC encourage this sort of arrangement. Even if the different layers are written in the same language, it's not necessarily a good idea for the underlying model objects to have methods like makeQtWidgets(), since it requires that layer to know not only about the GUI library but also about the layout and control flow of the user interface.
A practical point: to avoid the situation where a derived class fails to specify its type, the base class should require the value in its constructor:
struct Base {
enum Type { derived1, derived2 };
Base(Type t) : typ(t) { /* ... */ }
virtual ~Base()=0;
Type getType() const {return typ;}
// ...
private:
Type typ;
};
struct Derived1 : Base {
Derived1() : Base(derived1) { /* ... */ }
// ...
};
You might as well put the enum of all possibilities in the base class, since there must already be a central registry of the value for each derived class even if it's just on paper. This is a downside beyond the several mentioned by others: this design requires that all the classes be centrally managed, with no possibility for independent extension.
Finally, despite that inflexibility the clients must always confront the ugly possibility of an object of an unexpected type:
void foo(const Base &b) {
switch(b.getType()) {
case Base::derived1: /* ... */ break;
case Base::derived2: /* ... */ break;
default:
// what goes here?
}
}
Let's say I have a parent class, Arbitrary, and two child classes, Foo and Bar. I'm trying to implement a function to insert any Arbitrary object into a database, however, since the child classes contain data specific to those classes, I need to perform slightly different operations depending on the type.
Coming into C++ from Java/C#, my first instinct was to have a function that takes the parent as the parameter use something like instanceof and some if statements to handle child-class-specific behavior.
Pseudocode:
void someClass(Arbitrary obj){
obj.doSomething(); //a member function from the parent class
//more operations based on parent class
if(obj instanceof Foo){
//do Foo specific stuff
}
if(obj instanceof Bar){
//do Bar specific stuff
}
}
However, after looking into how to implement this in C++, the general consensus seemed to be that this is poor design.
If you have to use instanceof, there is, in most cases, something wrong with your design. – mslot
I considered the possibility of overloading the function with each type, but that would seemingly lead to code duplication. And, I would still end up needing to handle the child-specific behavior in the parent class, so that wouldn't solve the problem anyway.
So, my question is, what's the better way of performing operations that where all parent and child classes should be accepted as input, but in which behavior is dictated by the object type?
First, you want to take your Arbitrary by pointer or reference, otherwise you will slice off the derived class. Next, sounds like a case of a virtual method.
void someClass(Arbitrary* obj) {
obj->insertIntoDB();
}
where:
class Arbitrary {
public:
virtual ~Arbitrary();
virtual void insertIntoDB() = 0;
};
So that the subclasses can provide specific overrides:
class Foo : public Arbitrary {
public:
void insertIntoDB() override
// ^^^ if C++11
{
// do Foo-specific insertion here
}
};
Now there might be some common functionality in this insertion between Foo and Bar... so you should put that as a protected method in Arbitrary. protected so that both Foo and Bar have access to it but someClass() doesn't.
In my opinion, if at any place you need to write
if( is_instance_of(Derived1) )
//do something
else if ( is_instance_of(Derived2) )
//do somthing else
...
then it's as sign of bad design. First and most straight forward issue is that of "Maintainence". You have to take care in case further derivation happens. However, sometimes it's necessary. for e.g if your all classes are part of some library. In other cases you should avoid this coding as far as possible.
Most often you can remove the need to check for specific instance by introducing some new classes in the hierarchy. For e.g :-
class BankAccount {};
class SavingAccount : public BankAccount { void creditInterest(); };
class CheckingAccount : public BankAccount { void creditInterest(): };
In this case, there seems to be a need for if/else statement to check for actual object as there is no corresponsing creditInterest() in BanAccount class. However, indroducing a new class could obviate the need for that checking.
class BankAccount {};
class InterestBearingAccount : public BankAccount { void creditInterest(): } {};
class SavingAccount : public InterestBearingAccount { void creditInterest(): };
class CheckingAccount : public InterestBearingAccount { void creditInterest(): };
The issue here is that this will arguably violate SOLID design principles, given that any extension in the number of mapped classes would require new branches in the if statement, otherwise the existing dispatch method will fail (it won't work with any subclass, just those it knows about).
What you are describing looks well suited to inheritance polymorphicism - each of Arbitrary (base), Foo and Bar can take on the concerns of its own fields.
There is likely to be some common database plumbing which can be DRY'd up the base method.
class Arbitrary { // Your base class
protected:
virtual void mapFields(DbCommand& dbCommand) {
// Map the base fields here
}
public:
void saveToDatabase() { // External caller invokes this on any subclass
openConnection();
DbCommand& command = createDbCommand();
mapFields(command); // Polymorphic call
executeDbTransaction(command);
}
}
class Foo : public Arbitrary {
protected: // Hide implementation external parties
virtual void mapFields(DbCommand& dbCommand) {
Arbitrary::mapFields();
// Map Foo specific fields here
}
}
class Bar : public Arbitrary {
protected:
virtual void mapFields(DbCommand& dbCommand) {
Arbitrary::mapFields();
// Map Bar specific fields here
}
}
If the base class, Arbitrary itself cannot exist in isolation, it should also be marked as abstract.
As StuartLC pointed out, the current design violates the SOLID principles. However, both his answer and Barry's answer has strong coupling with the database, which I do not like (should Arbitrary really need to know about the database?). I would suggest that you make some additional abstraction, and make the database operations independent of the the data types.
One possible implementation may be like:
class Arbitrary {
public:
virtual std::string serialize();
static Arbitrary* deserialize();
};
Your database-related would be like (please notice that the parameter form Arbitrary obj is wrong and can truncate the object):
void someMethod(const Arbitrary& obj)
{
// ...
db.insert(obj.serialize());
}
You can retrieve the string from the database later and deserialize into a suitable object.
So, my question is, what's the better way of performing operations
that where all parent and child classes should be accepted as input,
but in which behavior is dictated by the object type?
You can use Visitor pattern.
#include <iostream>
using namespace std;
class Arbitrary;
class Foo;
class Bar;
class ArbitraryVisitor
{
public:
virtual void visitParent(Arbitrary& m) {};
virtual void visitFoo(Foo& vm) {};
virtual void visitBar(Bar& vm) {};
};
class Arbitrary
{
public:
virtual void DoSomething()
{
cout<<"do Parent specific stuff"<<endl;
}
virtual void accept(ArbitraryVisitor& v)
{
v.visitParent(*this);
}
};
class Foo: public Arbitrary
{
public:
virtual void DoSomething()
{
cout<<"do Foo specific stuff"<<endl;
}
virtual void accept(ArbitraryVisitor& v)
{
v.visitFoo(*this);
}
};
class Bar: public Arbitrary
{
public:
virtual void DoSomething()
{
cout<<"do Bar specific stuff"<<endl;
}
virtual void accept(ArbitraryVisitor& v)
{
v.visitBar(*this);
}
};
class SetArbitaryVisitor : public ArbitraryVisitor
{
void visitParent(Arbitrary& vm)
{
vm.DoSomething();
}
void visitFoo(Foo& vm)
{
vm.DoSomething();
}
void visitBar(Bar& vm)
{
vm.DoSomething();
}
};
int main()
{
Arbitrary *arb = new Foo();
SetArbitaryVisitor scv;
arb->accept(scv);
}
I'm finding it difficult to describe this problem very concisely, so I've attached the code for a demonstration program.
The general idea is that we want a set of Derived classes that are forced to implement some abstract Foo() function from a Base class. Each of the derived Foo() calls must accept a different parameter as input, but all of the parameters should also be derived from a BaseInput class.
We see two possible solutions so far, neither we're very happy with:
Remove the Foo() function from the base class and reimplement it with the correct input types in each Derived class. This, however, removes the enforcement that it be implemented in the same manner in each derived class.
Do some kind of dynamic cast inside the receiving function to verify that the type received is correct. However, this does not prevent the programmer from making an error and passing the incorrect input data type. We would like the type to be passed to the Foo() function to be compile-time correct.
Is there some sort of pattern that could enforce this kind of behaviour? Is this whole idea breaking some sort of fundamental idea underlying OOP? We'd really like to hear your input on possible solutions outside of what we've come up with.
Thanks so much!
#include <iostream>
// these inputs will be sent to our Foo function below
class BaseInput {};
class Derived1Input : public BaseInput { public: int d1Custom; };
class Derived2Input : public BaseInput { public: float d2Custom; };
class Base
{
public:
virtual void Foo(BaseInput& i) = 0;
};
class Derived1 : public Base
{
public:
// we don't know what type the input is -- do we have to try to cast to what we want
// and see if it works?
virtual void Foo(BaseInput& i) { std::cout << "I don't want to cast this..." << std::endl; }
// prefer something like this, but then it's not overriding the Base implementation
//virtual void Foo(Derived1Input& i) { std::cout << "Derived1 did something with Derived1Input..." << std::endl; }
};
class Derived2 : public Base
{
public:
// we don't know what type the input is -- do we have to try to cast to what we want
// and see if it works?
virtual void Foo(BaseInput& i) { std::cout << "I don't want to cast this..." << std::endl; }
// prefer something like this, but then it's not overriding the Base implementation
//virtual void Foo(Derived2Input& i) { std::cout << "Derived2 did something with Derived2Input..." << std::endl; }
};
int main()
{
Derived1 d1; Derived1Input d1i;
Derived2 d2; Derived2Input d2i;
// set up some dummy data
d1i.d1Custom = 1;
d2i.d2Custom = 1.f;
d1.Foo(d2i); // this compiles, but is a mistake! how can we avoid this?
// Derived1::Foo() should only accept Derived1Input, but then
// we can't declare Foo() in the Base class.
return 0;
}
Since your Derived class is-a Base class, it should never tighten the base contract preconditions: if it has to behave like a Base, it should accept BaseInput allright. This is known as the Liskov Substitution Principle.
Although you can do runtime checking of your argument, you can never achieve a fully type-safe way of doing this: your compiler may be able to match the DerivedInput when it sees a Derived object (static type), but it can not know what subtype is going to be behind a Base object...
The requirements
DerivedX should take a DerivedXInput
DerivedX::Foo should be interface-equal to DerivedY::Foo
contradict: either the Foo methods are implemented in terms of the BaseInput, and thus have identical interfaces in all derived classes, or the DerivedXInput types differ, and they cannot have the same interface.
That's, in my opinion, the problem.
This problem occured to me, too, when writing tightly coupled classes that are handled in a type-unaware framework:
class Fruit {};
class FruitTree {
virtual Fruit* pick() = 0;
};
class FruitEater {
virtual void eat( Fruit* ) = 0;
};
class Banana : public Fruit {};
class BananaTree {
virtual Banana* pick() { return new Banana; }
};
class BananaEater : public FruitEater {
void eat( Fruit* f ){
assert( dynamic_cast<Banana*>(f)!=0 );
delete f;
}
};
And a framework:
struct FruitPipeLine {
FruitTree* tree;
FruitEater* eater;
void cycle(){
eater->eat( tree->pick() );
}
};
Now this proves a design that's too easily broken: there's no part in the design that aligns the trees with the eaters:
FruitPipeLine pipe = { new BananaTree, new LemonEater }; // compiles fine
pipe.cycle(); // crash, probably.
You may improve the cohesion of the design, and remove the need for virtual dispatching, by making it a template:
template<class F> class Tree {
F* pick(); // no implementation
};
template<class F> class Eater {
void eat( F* f ){ delete f; } // default implementation is possible
};
template<class F> PipeLine {
Tree<F> tree;
Eater<F> eater;
void cycle(){ eater.eat( tree.pick() ); }
};
The implementations are really template specializations:
template<> class Tree<Banana> {
Banana* pick(){ return new Banana; }
};
...
PipeLine<Banana> pipe; // can't be wrong
pipe.cycle(); // no typechecking needed.
You might be able to use a variation of the curiously recurring template pattern.
class Base {
public:
// Stuff that don't depend on the input type.
};
template <typename Input>
class Middle : public Base {
public:
virtual void Foo(Input &i) = 0;
};
class Derived1 : public Middle<Derived1Input> {
public:
virtual void Foo(Derived1Input &i) { ... }
};
class Derived2 : public Middle<Derived2Input> {
public:
virtual void Foo(Derived2Input &i) { ... }
};
This is untested, just a shot from the hip!
If you don't mind the dynamic cast, how about this:
Class BaseInput;
class Base
{
public:
void foo(BaseInput & x) { foo_dispatch(x); };
private:
virtual void foo_dispatch(BaseInput &) = 0;
};
template <typename TInput = BaseInput> // default value to enforce nothing
class FooDistpatch : public Base
{
virtual void foo_dispatch(BaseInput & x)
{
foo_impl(dynamic_cast<TInput &>(x));
}
virtual void foo_impl(TInput &) = 0;
};
class Derived1 : public FooDispatch<Der1Input>
{
virtual void foo_impl(Der1Input & x) { /* your implementation here */ }
};
That way, you've built the dynamic type checking into the intermediate class, and your clients only ever derive from FooDispatch<DerivedInput>.
What you are talking about are covariant argument types, and that is quite an uncommon feature in a language, as it breaks your contract: You promised to accept a base_input object because you inherit from base, but you want the compiler to reject all but a small subset of base_inputs...
It is much more common for programming languages to offer the opposite: contra-variant argument types, as the derived type will not only accept everything that it is bound to accept by the contract, but also other types.
At any rate, C++ does not offer contravariance in argument types either, only covariance in the return type.
C++ has a lot of dark areas, so it's hard to say any specific thing is undoable, but going from the dark areas I do know, without a cast, this cannot be done. The virtual function specified in the base class requires the argument type to remain the same in all the children.
I am sure a cast can be used in a non-painful way though, perhaps by giving the base class an Enum 'type' member that is uniquely set by the constructor of each possible child that might possibly inherit it. Foo() can then check that 'type' and determine which type it is before doing anything, and throwing an assertion if it is surprised by something unexpected. It isn't compile time, but it's the closest a compromise I can think of, while still having the benefits of requiring a Foo() be defined.
It's certainly restricted, but you can use/simulate coviarance in constructors parameters.
I have this pimpl design where the implementation classes are polymorphic but the interfaces are supposed to just contain a pointer, making them polymorphic somewhat defeats the purpose of the design.
So I create my Impl and Intf base classes to provide reference counting. And then the user can create their implementations. An example:
class Impl {
mutable int _ref;
public:
Impl() : _ref(0) {}
virtual ~Impl() {}
int addRef() const { return ++_ref; }
int decRef() const { return --_ref; }
};
template <typename TImpl>
class Intf {
TImpl* impl;
public:
Intf(TImpl* t = 0) : impl(0) {}
Intf(const Intf& other) : impl(other.impl) { if (impl) impl->addRef(); }
Intf& operator=(const Intf& other) {
if (other.impl) other.impl->addRef();
if (impl && impl->decRef() <= 0) delete impl;
impl = other.impl;
}
~Intf() { if (impl && impl->decRef() <= 0) delete impl; }
protected:
TImpl* GetImpl() const { return impl; }
void SetImpl(... //etc
};
class ShapeImpl : public Impl {
public:
virtual void draw() = 0;
};
class Shape : public Intf<ShapeImpl> {
public:
Shape(ShapeImpl* i) : Intf<ShapeImpl>(i) {}
void draw() {
ShapeImpl* i = GetImpl();
if (i) i->draw();
}
};
class TriangleImpl : public ShapeImpl {
public:
void draw();
};
class PolygonImpl : public ShapeImpl {
public:
void draw();
void addSegment(Point a, Point b);
};
Here is where have the issue. There are two possible declaration for class Polygon:
class Polygon1 : public Intf<PolygonImpl> {
public:
void draw() {
PolygonImpl* i = GetImpl();
if (i) i->draw();
}
void addSegment(Point a, Point b) {
PolygonImpl* i = GetImpl();
if (i) i->addSegment(a,b);
}
};
class Polygon2 : public Shape {
void addSegment(Point a, Point b) {
ShapeImpl* i = GetImpl();
if (i) dynamic_cast<Polygon*>(i)->addSegment(a,b);
}
}
In the Polygon1, I have rewrite the code for draw because I have not inherited it. In Polygon2 I need ugly dynamic casts because GetImpl() doesn't know about PolygonImpl. What I would like to do is something like this:
template <typename TImpl>
struct Shape_Interface {
void draw() {
TImpl* i = GetImpl();
if (i) i->draw();
}
};
template <typename TImpl>
struct Polygon_Interface : public Shape_Interface<Timpl> {
void addSegment(Point a, Point b) { ... }
};
class Shape : public TIntf<ShapeImpl>, public Shape_Interface<ShapeImpl> {...};
class Polygon : public TIntf<PolygonImpl>, public Polygon_Interface<PolygonImpl> {
public:
Polygon(PolygonImpl* i) : TIntf<PolygonImpl>(i) {}
};
But of course there's a problem here. I can't access GetImpl() from the Interface classes unless I derive them from Intf. And if I do that, I need to make Intf virtual everywhere it appears.
template <typename TImpl>
class PolygonInterface : public virtual Intf<TImpl> { ... };
class Polygon : public virtual Intf<PolygonImpl>, public PolygonInterface { ... }
OR I can store a TImpl*& in each Interface and construct them with a reference to the base Intf::impl. But that just means I have a pointer pointing back into myself for every interface included.
template <typename TImpl>
class PolygonInterface {
TImpl*& impl;
public:
PolygonInterface(TImpl*& i) : impl(i) {}
...};
Both of these solutions bloat the Intf class, add an extra dereference, and basically provide no benefit over straight polymorphism.
So, the question is, is there a third way, that I've missed that would solve this issue besides just duplicating the code everywhere (with its maintenance issues)?
TOTALLY SHOULD, BUT DOESN'T WORK: I wish there were base classes unions that just overlaid the class layouts and, for polymorphic classes, required that they have the exact same vtable layout. Then both Intf and ShapeInterface would each declare a single T* element and access it identically:
class Shape : public union Intf<ShapeImpl>, public union ShapeInterface<ShapeImpl> {};
I should note that your Impl class is nothing more than the reimplementation of a shared_ptr without the thread safety and all those cast bonuses.
Pimpl is nothing but a technic to avoid needless compile-time dependencies.
You do not need to actually know how a class is implemented to inherit from it. It would defeat the purpose of encapsulation (though your compiler does...).
So... I think that you are not trying to use Pimpl here. I would rather think this is a kind of Proxy patterns, since apparently:
Polygon1 numberOne;
Polygon2 numberTwo = numberOne;
numberTwo.changeData(); // affects data from numberOne too
// since they point to the same pointer!!
If you want to hide implementation details
Use Pimpl, but the real one, it means copying in depth during copy construction and assignment rather than just passing the pointer around (whether ref-counted or not, though ref-counted is preferable of course :) ).
If you want a proxy class
Just use a plain shared_ptr.
For inheritance
It does not matter, when you inherit from a class, how its private members are implemented. So just inherit from it.
If you want to add some new private members (usual case), then:
struct DerivedImpl;
class Derived: public Base // Base implemented with a Pimpl
{
public:
private:
std::shared_ptr<DerivedImpl> _data;
};
There is not much difference with classic implementation, as you can see, just that there is a pointer in lieu of a bunch of data.
BEWARE
If you forward declare DerivedImpl (which is the goal of Pimpl), then the destructor automatically generated by the compiler is... wrong.
The problem is that in order to generate the code for the destructor, the compiler needs the definition of DerivedImpl (ie: a complete type) in order to know how to destroy it, since a call to delete is hidden in the bowels of shared_ptr. However it may only generate a warning at compilation time (but you'll have a memory leak).
Furthermore, if you want an in-depth copy (rather than a shallow one, which consists in the copy and the original both pointing to the same DerivedImpl instance), you will also have to define manually the copy-constructor AND the assignment operator.
You may decide to create a better class that shared_ptr which will have deep-copy semantics (which could be called member_ptr as in cryptopp, or just Pimpl ;) ). This introduce a subtle bug though: while the code generated for the copy-constructor and the assignement operator could be thought of as correct, they are not, since once again you need a complete type (and thus the definition of DerivedImpl), so you will have to write them manually.
This is painful... and I'm sorry for you.
EDIT: Let's have a Shape discussion.
// Shape.h
namespace detail { class ShapeImpl; }
class Shape
{
public:
virtual void draw(Board& ioBoard) const = 0;
private:
detail::ShapeImpl* m_impl;
}; // class Shape
// Rectangle.h
namespace detail { class RectangleImpl; }
class Rectangle: public Shape
{
public:
virtual void draw(Board& ioBoard) const;
size_t getWidth() const;
size_t getHeight() const;
private:
detail::RectangleImpl* m_impl;
}; // class Rectangle
// Circle.h
namespace detail { class CircleImpl; }
class Circle: public Shape
{
public:
virtual void draw(Board& ioBoard) const;
size_t getDiameter() const;
private:
detail::CircleImpl* m_impl;
}; // class Circle
You see: neither Circle nor Rectangle care if Shape uses Pimpl or not, as its name implies, Pimpl is an implementation detail, something private that is not shared with the descendants of the class.
And as I explained, both Circle and Rectangle use Pimpl too, each with their own 'implementation class' (which can be nothing more than a simple struct with no method by the way).
I think you were right in that I didn't understand your question initially.
I think you're trying to force a square shape into a round hole... it don't quite fit C++.
You can force that your container holds pointers to objects of a given base-layout, and then allow objects of arbitrary composition to be actually pointed to from there, assuming that you as a programmer only actually place objects that in fact have identical memory layouts (member-data - there's no such thing as member-function-layout for a class unless it has virtuals, which you wish to avoid).
std::vector< boost::shared_ptr<IShape> > shapes;
NOTE at the absolute MINIMUM, you must still have a virtual destructor defined in IShape, or object deletion is going to fail miserably
And you could have classes which all take a pointer to a common implementation core, so that all compositions can be initialized with the element that they share (or it could be done statically as a template via pointer - the shared data).
But the thing is, if I try to create an example, I fall flat the second I try to consider: what is the data shared by all shapes? I suppose you could have a vector of Points, which then could be as large or small as any shape required. But even so, Draw() is truly polymorphic, it isn't an implementation that can possibly be shared by multiple types - it has to be customized for various classifications of shapes. i.e. a circle and a polygon cannot possibly share the same Draw(). And without a vtable (or some other dynamic function pointer construct), you cannot vary the function called from some common implementation or client.
Your first set of code is full of confusing constructs. Maybe you can add a new, simplified example that PURELY shows - in a more realistic way - what you're trying to do (and ignore the fact that C++ doesn't have the mechanics you want - just demonstrate what your mechanic should look like).
To my mind, I just don't get the actual practical application, unless you're tyring to do something like the following:
Take a COM class, which inherits from two other COM Interfaces:
class MyShellBrowserDialog : public IShellBrowser, public ICommDlgBrowser
{
...
};
And now I have a diamond inheritence pattern: IShellBrowser inherits ultimately from IUnknown, as does ICommDlgBrowser. But it seems incredibly silly to have to write my own IUnknown:AddRef and IUnknown::Release implementation, which is a highly standard implementation, because there's no way to cause the compiler to let another inherited class supply the missing virtual functions for IShellBrowser and/or ICommDlgBrowser.
i.e., I end up having to:
class MyShellBrowserDialog : public IShellBrowser, public ICommDlgBrowser
{
public:
virtual ULONG STDMETHODCALLTYPE AddRef(void) { return ++m_refcount; }
virtual ULONG STDMETHODCALLTYPE Release(void) { return --m_refcount; }
...
}
because there's no way I know of to "inherit" or "inject" those function implementations into MyShellBrowserDialog from anywhere else which actually fill-in the needed virtual member function for either IShellBrowser or ICommDlgBrowser.
I can, if the implementations were more complex, manually link up the vtable to an inherited implementor if I wished:
class IUnknownMixin
{
ULONG m_refcount;
protected:
IUnknonwMixin() : m_refcount(0) {}
ULONG AddRef(void) { return ++m_refcount; } // NOTE: not virutal
ULONG Release(void) { return --m_refcount; } // NOTE: not virutal
};
class MyShellBrowserDialog : public IShellBrowser, public ICommDlgBrowser, private IUnknownMixin
{
public:
virtual ULONG STDMETHODCALLTYPE AddRef(void) { return IUnknownMixin::AddRef(); }
virtual ULONG STDMETHODCALLTYPE Release(void) { return IUnknownMixin::Release(); }
...
}
And if I needed the mix-in to actually refer to the most-derived class to interact with it, I could add a template parameter to IUnknownMixin, to give it access to myself.
But what common elements could my class have or benefit by that IUnknownMixin couldn't itself supply?
What common elements could any composite class have that various mixins would want to have access to, which they needed to derive from themselves? Just have the mixins take a type parameter and access that. If its instance data in the most derived, then you have something like:
template <class T>
class IUnknownMixin
{
T & const m_outter;
protected:
IUnknonwMixin(T & outter) : m_outter(outter) {}
// note: T must have a member m_refcount
ULONG AddRef(void) { return ++m_outter.m_refcount; } // NOTE: not virtual
ULONG Release(void) { return --m_outter.m_refcount; } // NOTE: not virtual
};
Ultimately your question remains somewhat confusing to me. Perhaps you could create that example that shows your preferred-natural-syntax that accomplishes something clearly, as I just don't see that in your initial post, and I can't seem to sleuth it out from toying with these ideas myself.
I have seen lots of solutions to this basic conundrum: polymorphism + variation in interfaces.
One basic approach is to provide a way to query for extended interfaces - so you have something along the lines of COM programming under Windows:
const unsigned IType_IShape = 1;
class IShape
{
public:
virtual ~IShape() {} // ensure all subclasses are destroyed polymorphically!
virtual bool isa(unsigned type) const { return type == IType_IShape; }
virtual void Draw() = 0;
virtual void Erase() = 0;
virtual void GetBounds(std::pair<Point> & bounds) const = 0;
};
const unsigned IType_ISegmentedShape = 2;
class ISegmentedShape : public IShape
{
public:
virtual bool isa(unsigned type) const { return type == IType_ISegmentedShape || IShape::isa(type); }
virtual void AddSegment(const Point & a, const Point & b) = 0;
virtual unsigned GetSegmentCount() const = 0;
};
class Line : public IShape
{
public:
Line(std::pair<Point> extent) : extent(extent) { }
virtual void Draw();
virtual void Erase();
virtual void GetBounds(std::pair<Point> & bounds);
private:
std::pair<Point> extent;
};
class Polygon : public ISegmentedShape
{
public:
virtual void Draw();
virtual void Erase();
virtual void GetBounds(std::pair<Point> & bounds);
virtual void AddSegment(const Point & a, const Point & b);
virtual unsigned GetSegmentCount() const { return vertices.size(); }
private:
std::vector<Point> vertices;
};
Another option would be to make a single richer base interface class - which has all the interfaces you need, and then to simply define a default, no-op implementation for those in the base class, which returns false or throws to indicate that it isn't supported by the subclass in question (else the subclass would have provided a functional implementation for this member function).
class Shape
{
public:
struct Unsupported
{
Unsupported(const std::string & operation) : bad_op(operation) {}
const std::string & AsString() const { return bad_op; }
std::string bad_op;
};
virtual ~Shape() {} // ensure all subclasses are destroyed polymorphically!
virtual void Draw() = 0;
virtual void Erase() = 0;
virtual void GetBounds(std::pair<Point> & bounds) const = 0;
virtual void AddSegment(const Point & a, const Point & b) { throw Unsupported("AddSegment"); }
virtual unsigned GetSegmentCount() const { throw Unsupported("GetSegmentCount"); }
};
I hope that this helps you to see some possibilities.
Smalltalk had the wonderful attribute of being able to ask the meta-type-system whether a given instance supported a particular method - and it supported having a class-handler that could execute anytime a given instance was told to perform an operation it didn't support - along with what operation that was, so you could forward it as a proxy, or you could throw a different error, or simply quietly ignore that operation as a no-op).
Objective-C supports all of those same modalities as Smalltalk! Very, very cool things can be accomplished by having access to the type-system at runtime. I assume that .NET can pull of some crazy cool stuff along those lines (though I doubt that its nearly as elegant as Smalltalk or Objective-C, from what I've seen).
Anyway, ... good luck :)