Polymorphism and casting through struct with pointers - c++

Full disclaimer first: I have not compiled this example code, nor the real code (well, at least fully deployed). I am still wrapping my head around the problem. With that in mind, say we have this class structure:
A super base class that we will use to store instances with this base in the same container and a few "Facet" classes that we will use with multiple inheritance to encapsulate common behaviour.
class Facet_A;
class Facet_B;
class Facet_C;
struct Facet_converter
{
Facet_A * facet_a;
Facet_B * facet_b;
Facet_C * facet_c;
};
class Super_base
{
public:
virtual ~Super_base() {}
virtual Facet_converter convert()=0;
virtual const Facet_converter convert()const=0; //Notice this const...
};
class Facet_A
{
private:
int value_a;
public:
virtual ~Facet_A() {}
Facet_A():value_a(0) {}
void set_value_a(int v) {value_a=v;}
int get_value_a() const {return value_a;}
};
class Facet_B
{
private:
float value_b;
public:
Facet_B():value_b(0) {}
virtual ~Facet_B() {}
void set_value_b(float v) {value_b=v;}
float get_value_b() const {return value_b;}
};
class Facet_C
{
private:
char value_c;
public:
Facet_C():value_c('a') {}
virtual ~Facet_C() {}
void set_value_c(char v) {value_c=v;}
char get_value_c() const {return value_c;}
};
All classes that derive from these will always:
Use Super_base as a public base class, so we can store them in a vector of these.
Implement the convert methods that will return a Facet_converter object with pointers (shared, unique, raw, whatever) of the derived class casted as a particular facet (null, if not applicable).
Use Facet_A, Facet_B or Facet_C as a base class depending on what do they try to implement.
The client code would do something like...
std::vector<Super_base *> v;
//Fill super base with the good stuff.
//Let's use everything that has an integer!.
for(auto sb : v)
{
Facet_converter fc=sb->convert();
if(fc.facet_a)
{
//Do something with this integer like... std::cout<<fc.facet_a->get_value_a()<<std::endl;
}
}
//Let's use everything that has a float.
for(auto sb : v)
{
Facet_converter fc=sb->convert();
if(fc.facet_b)
{
//Do something with this float...
}
}
//Let's use everything that has a char.
for(auto sb : v)
{
Facet_converter fc=sb->convert();
if(fc.facet_c)
{
//You get the drift...
}
}
Horrible design apart (I've come to this point sick of visitors everywhere) this particular example is pretty much barebones, but you get what I am trying to do: casting down the hierarchy without using dynamic_cast and "enforcing" the compiler help (it would yell at me if I tried an assignment to a non-base class in the "convert" method).
So, a of fully implemented class...
class Derived_numeric: //This one has a float and and int
public Super_base,
public Facet_A,
public Facet_B
{
///Blah blah blah blah
virtual Facet_converter convert()
{
Facet_converter result;
result.facet_a=this;
result.facet_b=this;
result.facet_c=nullptr; //Assume no constructor for the struct that initializes the method, not really the case.
return result;
}
virtual const Facet_converter convert()const
{
const Facet_converter result;
result.facet_a=this; //Booom!!!. Error, const Derived_numeric can't be caster to Facet_A because... it's const.
result.facet_b=this;
result.facet_c=nullptr;
return result;
}
}
And there's the problem, right in the const convert method. There's a const and a non const method because the client code may work with const and non const objects but there's no way the compiler is gonna let me assign a "const this" without const casting it first.
Considering that I've come with two solutions:
const_casting the this pointer in the const method.
Creating two Facet_converter objects: Facet_converter and Facet_converter_const. They're exactly the same but one has const pointers and the other has regular pointers. Let the client code use the one they need.
Both of them suffer from horrible code repetition, since the code is almost the same and only a few details change.
I've toyed with the idea of implementing only the const one, const_casting the "this" pointer and basically lying about what the method promises. Want true constness?, add the const modifier to the result of convert() and be done with it... Seems easier, but too sneaky.
My question is, can I implement this idea without basically copying and pasting the code and being sneaky?. Remember that I need both const and non const (the derived object may change its state by using the facets, or it may not).
Now, please consider that I am not looking for "Your approach is wrong" or "I don't know why you would want to do that". This is the current situation I want to deal with and learn about. I already know I can use double dispatching or I can bastardize the whole base class to contain every other possibility... I am just looking for alternatives to it.

You could make a const Facet_converter member of Super_base and then set it via a constructor.
class Super_base
{
protected:
const Facet_converter implementations;
public:
Super_base( const Facet_converter& implementations )
: implementations( implementations ) {};
virtual ~Super_base() {};
const Facet_converter& convert() const { return implementations; }
};
When you implement the derived class, do:
Derived_numeric::Derived_numeric( ) : Super_base( Facet_converter( this, this, NULL ) )
You also need to add a constructor for the struct so that call is possible:
struct Facet_converter
{
Facet_converter( Facet_A* const& a, Facet_B* const& b, Facet_C* const& c )
{
facet_a = a;
facet_b = b;
facet_c = c;
}
Facet_A * facet_a;
Facet_B * facet_b;
Facet_C * facet_c;
};
I haven't tested this using actual pointers and subclasses, so it might need some tweaks.

Related

Best way to store std::vector of derived class in a host parent class

I want to store a std::vector<> containing objects which have a common base class, within a host class. The host class should remain copiable since it is stored inside a std::vector<> of it's owner class.
C++ offers multiple ways of doing that, but I want to know the best practice.
Here is an example using std::shared_ptr<>:
class Base{};
class Derivative1: public Base{};
class Derivative2: public Base{};
class Host{
public: std::vector<std::shared_ptr<Base>> _derivativeList_{};
};
class Owner{
public: std::vector<Host> _hostList_;
};
int main(int argc, char** argv){
Owner o;
o._hostList_.resize(10);
Host& h = o._hostList_[0];
h._derivativeList_.emplace_back(std::make_shared<Derivative1>());
// h._derivativeList_.resize(10, std::make_shared<Derivative1>()); // all elements share the same pointer, but I don't want that.
}
Here the main drawback for me is that in order to claim a lot of elements in _derivativeList_ I need to perform emplace_back() for every single element. This takes a lot more time than a simple resize(N) which I can't use with std::shared_ptr<> since it will create the same pointer instance for every slot.
I thought about using std::unique_ptr<> instead, but this is not viable since it makes the Host class non copiable (a feature requested by std::vector).
Otherwise, I could use std::variant<Derived1, Derived2> which can do what I want. However I would need to declare every possible instance of the derived class...
Any thought/advice about this?
tldr: Use a variant or type erasure, depending on context.
What you are asking for in C++ would be described roughly as a value type or a type with value semantics. You want a type that is copyable, and copying just "does the right thing" (copies do not share ownership). But at the same time you want polymorphism. You want to hold a variety of types that satisfy the same interface. So... a polymorphic value type.
Value types are easier to work with, so they will make a more pleasant interface. But, they may actually perform worse, and they are more complex to implement. Therefore, as with everything, discretion and judgment come into play. But we can still talk about the "best practice" for implementing them.
Let's add an interface method so we can illustrate some of the relative merits below:
struct Base {
virtual ~Base() = default;
virtual auto name() const -> std::string = 0;
};
struct Derivative1: Base {
auto name() const -> std::string override {
return "Derivative1";
}
};
struct Derivative2: Base {
auto name() const -> std::string override {
return "Derivative2";
}
};
There are two common approaches: variants and type erasure. These are the best options we have in C++.
Variants
As you imply, variants are the best option when the set of types is finite and closed. Other developers are not expected to add to the set with their own types.
using BaseLike = std::variant<Derivative1, Derivative2>;
struct Host {
std::vector<BaseLike> derivativeList;
};
There's a downside to using the variant directly: BaseLike doesn't act like a Base. You can copy it, but it doesn't implement the interface. Any use of it requires visitation.
So you would wrap it with a small wrapper:
class BaseLike: public Base {
public:
BaseLike(Derivative1&& d1) : data(std::move(d1)) {}
BaseLike(Derivative2&& d2) : data(std::move(d2)) {}
auto name() const -> std::string override {
return std::visit([](auto&& d) { return d.name(); }, data);
}
private:
std::variant<Derivative1, Derivative2> data;
};
struct Host {
std::vector<BaseLike> derivativeList;
};
Now you have a list in which you can put both Derivative1 and Derivative2 and treat a reference to an element as you would any Base&.
What's interesting now is that Base is not providing much value. By virtue of the abstract method, you know that all derived classes correctly implement it. However, in this scenario, we know all the derived classes, and if they fail to implement the method, the visitation will fail to compile. So, Base is actually not providing any value.
struct Derivative1 {
auto name() const -> std::string {
return "Derivative1";
}
};
struct Derivative2 {
auto name() const -> std::string {
return "Derivative2";
}
};
If we need to talk about the interface we can do so by defining a concept:
template <typename T>
concept base_like = std::copyable<T> && requires(const T& t) {
{ t.name() } -> std::same_as<std::string>;
};
static_assert(base_like<Derivative1>);
static_assert(base_like<Derivative2>);
static_assert(base_like<BaseLike>);
In the end, this option looks like: https://godbolt.org/z/7YW9fPv6Y
Type Erasure
Suppose instead we have an open set of types.
The classical and simplest approach is to traffic in pointers or references to a common base class. If you also want ownership, put it in a unique_ptr. (shared_ptr is not a good fit.) Then, you have to implement copy operations, so put the unique_ptr inside a wrapper type and define copy operations. The classical approach is to define a method as part of the base class interface clone() which every derived class overrides to copy itself. The unique_ptr wrapper can call that method when it needs to copy.
That's a valid approach, although it has some tradeoffs. Requiring a base class is intrusive, and may be painful if you simultaneously want to satisfy multiple interfaces. std::vector<T> and std::set<T> do not share a common base class but both are iterable. Additionally, the clone() method is pure boilerplate.
Type erasure takes this one step more and removes the need for a common base class.
In this approach, you still define a base class, but for you, not your user:
struct Base {
virtual ~Base() = default;
virtual auto clone() const -> std::unique_ptr<Base> = 0;
virtual auto name() const -> std::string = 0;
};
And you define an implementation that acts as a type-specific delegator. Again, this is for you, not your user:
template <typename T>
struct Impl: Base {
T t;
Impl(T &&t) : t(std::move(t)) {}
auto clone() const -> std::unique_ptr<Base> override {
return std::make_unique<Impl>(*this);
}
auto name() const -> std::string override {
return t.name();
}
};
And then you can define the type-erased type that the user interacts with:
class BaseLike
{
public:
template <typename B>
BaseLike(B &&b)
requires((!std::is_same_v<std::decay_t<B>, BaseLike>) &&
base_like<std::decay_t<B>>)
: base(std::make_unique<detail::Impl<std::decay_t<B>>>(std::move(b))) {}
BaseLike(const BaseLike& other) : base(other.base->clone()) {}
BaseLike& operator=(const BaseLike& other) {
if (this != &other) {
base = other.base->clone();
}
return *this;
}
BaseLike(BaseLike&&) = default;
BaseLike& operator=(BaseLike&&) = default;
auto name() const -> std::string {
return base->name();
}
private:
std::unique_ptr<Base> base;
};
In the end, this option looks like: https://godbolt.org/z/P3zT9nb5o

C++ polymorphic functions with differing return types

I am creating a property class which stores a unique key and an arbitrary value as strings (plus an optional comment string for use when writing to configuration files). Currently I'm using the method of creating a base property class which holds the raw strings, and then subclassing this into type-specific properties - eg. an IntProperty which implements a getValue() function that converts the string to an int - to avoid having to convert a property value manually from a string every time I want to read it. These subclasses use getPropertyType(), a virtual function defined in the base and overridden in each of the derived, to return an enum value to identify which type of property they hold, and the base class returns a "none" identifier.
(As a side note, I shied away from templates because I'm using Qt and its required interface macro doesn't support templated objects. If it's worth using templates I may ditch the idea of using interfaces.)
My intention was to allow for lists of multiple different types of properties (string, int, float...) by subclassing them from the base property class and allowing arrays of base property pointers. However, I run into the problem that it then becomes very awkward to extract the property as a specific type from one of the derived classes, since the pointer to the base class obviously does not know about the newly defined getValue functions in the derived classes. I am left with either the option of extracting the string from the base class and converting manually or by casting the base class pointer to the correct derived class pointer. The first option renders the subclassing useless by requiring that I do the conversion manually, and the second sounds like a nightmare to code since there'll be a large switch statement involved on the property identifier value each time I want to work out which pointer to cast to.
What would be the most intelligent way of going about this problem? I want to keep the retrieval of property values as simple as possible - ie. have as little boilerplate code as I can to go from getting a base class pointer from an array to holding a properly typed copy of the property's value. Would it be worth considering the problem the other way around - have multiple strongly-typed property classes which all support getting and setting their respective value using a string?
What about this? (Untested, but you should get the idea)
class BaseType {
public:
virtual void getValue(string &s) { s = ""; };
virtual void getValue(int &i) { i = 0; };
virtual void getValue(double &d) { d = 0.0; };
};
class IntType : public BaseType {
public:
virtual void getValue(string &s) { s = to_string(myvalue); };
virtual void getValue(int &i) { i = myvalue; };
virtual void getValue(double &d) { d = static_cast<double>(myvalue); };
private:
int myvalue;
};
class DblType : public BaseType {
public:
virtual void getValue(string &s) { s = to_string(myvalue); };
virtual void getValue(int &i) { i = static_cast<int>myvalue; };
virtual void getValue(double &d) { d = myvalue; };
private:
double myvalue;
};
class StrType : public BaseType {
public:
virtual void getValue(string &s) { s = myvalue; };
virtual void getValue(int &i) { i = stoi(myvalue); };
virtual void getValue(double &d) { d = stod(myvalue); };
private:
string myvalue;
};
Surely, since the receiving side needs to know what type it's getting, using a name that indicates what you get back, e.g.
int GetInt(const string& key);
string GetString(const string& key);
double GetDouble(const string& key);
etc. would be just as good as calling it Get(const string& key) - and since the C++ language doesn't allow you to ONLY differentiate on the return type, that wouldn't work.
Another alternative is of course to have a
template <typename T>
void Get(const string& key, T& value);
(May need to actually implement all the different variant's differently, so it may not really help much to use a template, but it's much easier for me to write in an answer as a template! ;) )

STL: Initializing a container with an unconstructed stateful comparator

This has been running through my mind as a possible solution to an issue, however as it is a fairly obvious technical violation of something in C++, I wanted to know how likely to it is to fail, whether there is another fairly obvious approach, etc. I'm hoping this doesn't get into a flamewar about undefined behavior, but considering the topic I do expect a little bit.
This is not the code I'm writing, I'm hoping it's not too simplified to not describe what I am attempting to do.
class Code
{
public:
bool read(short slot, short& val);
bool read(short slot, long& val);
bool read(short slot, double& val);
// etc
protected:
unsigned char* m_data;
};
typedef boost::shared_ptr<Code> CodePtr;
class SortedBase
{
protected:
class Sorter : public std::binary_function<CodePtr,CodePtr,bool>
{
protected:
inline Sorter() {}
virtual ~Sorter() {}
public:
virtual bool operator()(CodePtr left, CodePtr right) PURE;
};
inline SortedBase(Sorter* s):m_codeList(s) {}
typedef std::set<CodePtr,Sorter> TSortedCode;
TSortedCode m_codeList;
public:
virtual ~SortedBase() {}
void fetch(); // populates m_codeList
};
template<class SORT1, class SORT2, class SORT3, class SORT4, class SORT5>
class SortedObject5 : public SortedBase
{
public:
SortedObject5():SortedBase(m_sorter),m_sorter(this) {}
something_interesting find(SORT1 val1, SORT2 val2, SORT3 val3, SORT4 val4, SORT5 val5);
protected:
typedef SortedObject5<SORT1,SORT2,SORT3,SORT4,SORT5> my_class;
class MySorter : public Sorter
{
public:
MySorter(const my_class& parent):m_parent(parent) {}
virtual operator()(CodePtr left, CodePtr right);
protected:
const my_class& m_parent;
}
MySorter m_sorter;
};
The intent here
I've often found when writing template classes that having a non-template base class with as much of the factored logic as possible is useful to both have some common class other code can reference and reduce the amount of code duplication, especially when making five different versions of the same class with different numbers of template parameters.
In this case the CodePtr is generated elsewhere in the code (although I did write it) and I would like to find elements based on an arbitrary number of arbitrary datatypes. I considered a std::multimap at first but the key would end up being a wrapper to (or a copy of a significant chunk of) the CodePtr again.
The problem
I am passing the stateful sorter functor SortedObject5<>::my_sorter to the constructor of SortedBase::m_codeList. However because the stateful sorter being in a sublcass, is fairly obviously not constructed at the point that the STL set is constructed.
I'm wondering if this is an issue if I don't make any inserts or searches in m_codeList from either constructor.
Stateful sorter disclaimer
I formally ASSERT() that the rules used by any stateful sort functor will change only while either the STL containers it controls are empty or will be clear()ed shortly afterwards.
The std::set<CodePtr,Sorter> object stores an instance of Sorter by value so when you construct it with a Sorter* (did you mean that to be a reference not a pointer?) it will slice the object and only keep the base part.
That means the Sorter copy constructor will run and make a copy of an uninitialized object. Undefined behaviour ensues.
That's assuming you can even create an instance of Sorter, if it's an abstract type you won't be able to (I don't know what your PURE does but I assume you're making the function pure virtual)
#Angew's comment suggest a good approach, the base from member idiom will allow you to ensure the m_sorter object is initialized first, which is part of the problem. That doesn't help the issue of slicing though, to solve that you'd need some wrapper around the sorter e.g.
typedef std::function<bool(const CodePtr&,const CodePtr&)> SorterFunc;
typedef std::set<CodePtr, SorterFunc> TSortedCode;
And then pass the wrapper to the set constructor:
inline SortedBase(SorterFunc s) : m_codeList(s) {}
If you construct the std::function from the derived type it won't be sliced. It will be copied though, but you can prevent that by using a reference wrapper:
SortedObject5() : BaseFrommember(this), SortedBase(SorterFunc(std::ref(m_sorter))) { }
Where m_sorter is already initialized, because it is stored in the BaseFromMember base class, using the base-from-member idiom.
This:
creates the m_sorter first so you don't do anything with an uninitialized object
passes it by reference to a SorterFunc object
uses a copy of that SorterFunc (still holding a reference to m_sorter) as the comparision function for the std::set
If you don't want to use the base-from-member idiom then it's still easy to avoid the undefined behaviour of your original code, just default construct the set (instead of passing it an uninitialized object) then assign a new value to it before you start populating it:
SortedObject5() : m_sorter(this)
{
this->m_codeList = TSortedCode(SorterFunc(boost::ref(m_sorter)));
}
No new base classes, no extra templates, no undefined behaviour.
Here's the working code in full:
class SortedBase
{
protected:
class Sorter : public std::binary_function<CodePtr,CodePtr,bool>
{
protected:
Sorter() {}
virtual ~Sorter() {}
public:
virtual bool operator()(const CodePtr& left, const CodePtr& right) = 0;
};
typedef boost::function<bool(const CodePtr&, const CodePtr&)> SorterFunc;
typedef std::set<CodePtr,SorterFunc> TSortedCode;
TSortedCode m_codeList;
public:
virtual ~SortedBase() {}
void fetch(); // populates m_codeList
};
template<class SORT1, class SORT2, class SORT3, class SORT4, class SORT5>
class SortedObject5 : public SortedBase
{
public:
SortedObject5() : m_sorter(*this)
{
this->m_codeList = TSortedCode(SorterFunc(boost::ref(m_sorter)));
}
protected:
typedef SortedObject5<SORT1,SORT2,SORT3,SORT4,SORT5> my_class;
class MySorter : public Sorter
{
public:
MySorter(const my_class& parent):m_parent(parent) {}
virtual bool operator()(const CodePtr& left, const CodePtr& right);
protected:
const my_class& m_parent;
};
MySorter m_sorter;
};

it is possible to change return type when override a virtual function in C++?

I encounter a problems about override virtual functions, in fact,it is about hessian (a web service protocol).
it has a base class Object, and some derived classes : Long,Int,String,...,all derived classes has a no-virtual function "value"
class Object
{
...
};
class Long :public Object
{
...
public:
typedef long long basic_type;
basic_type value(){return value_;}
private:
basic_type value_;
...
};
class Int :public Object
{
...
public:
typedef int basic_type;
basic_type value(){return value_;}
private:
basic_type value_;
...
};
now I want to add a function ,say, toString ,which can convert Object to a string:
Object *obj = ...
cout<<obj->toString();
if I can change the value function to virtual ,I only need to write a toString function in Object, else, I need to write a virtual function toString, and to override this functions in all derived classes.
for example
class Object
{
virtual Type value(); // It seemed that I can't write a function like this,because the Type is different for different derived classes
std::string toString()
{
some_convert_function(value());
}
};
but I can't write a virtual value function because of return value can't be override.
is there any good solution for this issue?
Thanks
it is possible to change return type when override a virtual function in C++?
Only in a very limited way, in that (raw) pointer or reference return type can be covariant.
is there any good solution for this issue?
Well, there are two fairly good solutions, and one slightly bad solution.
I'm giving you the slightly bad solution here. One reason that I'm giving that is that it's easy to understand, or at least it's quite easy to "copy and modify" even if one doesn't quite understand it. Another reason is that one of the good solutions requires some extensive general support machinery that there's no room for discussing here, and the other good solution (the one that in my opinion is best in nearly every respect) is of a kind that, at least when I have presented that kind of solution, has automatically received drive-by downvotes and only that, here on SO. I guess that that's the price to pay for the diversity here, which diversity is a Very Good Thing :-) But, unfortunately it means that there's no point in offering the real good stuff, I'd be down to negative rep then.
Anyways, code, based on dominance in virtual inheritance; it's about the same as inheriting an implementation of an interface in Java or C#:
#include <iostream>
#include <string>
#include <sstream>
//--------------------------------------- Machinery:
class ToStringInterface
{
public:
virtual std::string toString() const = 0;
};
template< typename ValueProvider >
class ToStringImpl
: public virtual ToStringInterface
{
public:
virtual std::string toString() const
{
ValueProvider const& self =
*static_cast<ValueProvider const*>( this );
std::ostringstream stream;
stream << self.value();
return stream.str();
}
};
//--------------------------------------- Usage example:
class Object
: public virtual ToStringInterface
{
// ...
};
class Long
: public Object
, public ToStringImpl< Long >
{
public:
typedef long long BasicType;
Long( BasicType v ): value_( v ) {}
BasicType value() const { return value_; }
private:
BasicType value_;
};
class Int
: public Object
, public ToStringImpl< Int >
{
public:
typedef int BasicType;
Int( BasicType v ): value_( v ) {}
BasicType value() const { return value_; }
private:
BasicType value_;
};
int main()
{
Object const& obj = Int( 42 );
std::cout << obj.toString() << std::endl;
}
If your Long and Int classes etc. are very similar, as they seem to be, consider defining just one class template, or perhaps inherit from specializations of such a template (this might also help avoid bugs, since it reduces redundancy).
EDIT: I see now that you have accepted an answer that is essentially just my last suggestion about templating. That means that I've answered the question as posed (a solution for distinct, different classes) while you had something less general in mind. Oh well.
Cheers & hth.,
No, you can't write toString in Object using a virtual 'value' function and override the return type. However you can write a virtual toString and with a template programming trick accomplish almost the same thing.
class Object
{
public:
virtual std::string toString();
}
template < class ValueType >
class BasicType : Object
{
public:
typedef ValueType basic_type;
basic_type value() { return value_; }
std::string toString()
{
return some_convert_function( value_ );
}
private:
basic_type value_;
}
typedef BasicType<long long> Long;
typedef BasicType<int> Int;
Unfortunately you can't overload functions in C++ by return value. What you could do, if you have the appropriate some_convert_function in place for all types you need it for would be to create free a template function that looks something like this:
template<typename T>
std::string toString(T const& t)
{
return some_convert_function<T>(t);
}
You can't override a function with a different return type; the closest you can come is to hide a function in the parent with a different one in the derived class. But that's not what you want, because the two will be different functions, completely unrelated.
You were correct in assuming that you'd need to create a new toString function in each derived class - that's what polymorphism is all about.
I don't think you're going about this the right way. While it is possible in some circumstances to change the return type of a virtual function, consider this: How is your function being used? If it's virtual, changes are that users will be using the base class. As such, they are oblivious as to what the actual type of your class is, and thus they wouldn't know what type to expect. So:
Either return the base class type.
Return functions that give you the proper type (i.e virtual std::string getStringValue(), which gives you a string if applicable).
Use templates, if the type is known by the user.
Regarding #MerickOWA comment, here's another solution, that does not requires any additional template mechanism.
Since you intended to have a virtual "value()" method that you needed to implement in all classes, I've extended the idea (usually, in these kind of framework, you've plenty of similar "basic" methods, so I've used a macro to write them for me, it's not required, it's just faster and less error prone.
#include <iostream>
#include <string>
#include <sstream>
struct Object
{
std::string toString() const { std::ostringstream str; getValue(str); return str.str(); }
virtual void getValue(std::ostringstream & str) const { str<<"BadObj"; }
};
// Add all the common "basic & common" function here
#define __BoilerPlate__ basic_type value; void getValue(std::ostringstream & str) const { str << value; }
// The only type specific part
#define MAKE_OBJ(T) typedef T basic_type; __BoilerPlate__
struct Long : public Object
{
MAKE_OBJ(long long)
Long() : value(345) {}
};
struct Int : public Object
{
MAKE_OBJ(long)
Int() : value(3) {}
};
int main()
{
Object a;
Long b;
Int c;
std::cout<<a.toString()<<std::endl; // BadObj
std::cout<<b.toString()<<std::endl; // 345
std::cout<<c.toString()<<std::endl; // 3
return 0;
}
Obviously, the trick is in the std::ostringstream classes that's accept any parameter type (long long, long, etc...). Since this is standard C++ practice, it should not matter.

PIMPL problem: How to have multiple interfaces to the impl w/o code duplication

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 :)