Related
Is it possible to find the size of a derived class object using a base class pointer, when you don't know the derived type.
Thank you.
There's no direct way, but you can write a virtual size() method child classes can implement. An intermediary templates class can automate the leg work.
struct base {
virtual size_t size() const =0;
virtual ~base() { }
};
template<typename T>
struct intermediate : base {
virtual size_t size() const { return sizeof(T); }
};
struct derived : intermediate<derived>
{ };
This does require your hierarchy be polymorphic... however, requesting behavior based on the dynamic type of an object rather than its static type is part of the definition of polymorphic behavior. So this won't add a v-table to the average use case, since at the very least you probably already have a virtual destructor.
This particular implementation does limit your inheritance tree to a single level without getting into multiple inheritance [ie, a type derived from derived will not get its own override of size]. There is a slightly more complex variant that gets around that.
struct base { /*as before */ };
template<typename Derived, typename Base>
struct intermediate : Base {
virtual size_t size() const { return sizeof(Derived); }
};
struct derived : intermediate<derived, base>
{ };
struct further_derived : intermediate<further_derived, derived>
{ };
Basically, this inserts an intermediate in between each actual layer of your hierarchy, each overriding size with the appropriate behavior, and deriving from the actual base type. Repeat ad nauseum.
//what you want
base >> derived
>> more_deriveder
>> most_derivedest
//what you get
base >> intermediate<derived, base>
>> derived >> intermediate<more_deriveder, derived>
>> more_deriveder >> intermediate<most_derivedest, more_deriveder>
>> most_derivedest
Several mixin-type libraries make use of such a scheme, such that the mixins can be added to an existing hierarchy without introducing multiple inheritance. Personally, I rarely use more than a single level of inheritance, so I don't bother with the added complexity, but your mileage may vary.
I don't think it can be done, because sizeof works on compile time types. You could define a virtual Size function in the base class and override it for each derived class.
Due to lack of reflection in C++, this is not generally possible with arbitrary classes at a whim. There are some workarounds however. You can write a virtual size() method as others have suggested. You can also use the Curiously Recurring Template Pattern, aka inheriting from Register<T> as well but I wouldn't recommend it, vtable costs 4 bytes per object, subclasses of T report incorrect size and correcting it results in multiple inheritance.
The best way would be to use a class to register, store and query dynamic size information, without modifying the class you want to query:
EDIT: As it turns out, due to the inconsistent semantics of typeid, it still needs classes with vtables, see the comments.
#include <cstddef>
#include <exception>
#include <iostream>
#include <map>
#include <typeinfo>
using namespace std;
class ClassNotFoundException
: public exception
{};
class Register
{
public:
template <class T>
static void reg (T* = NULL)
{
// could add other qualifiers
v[&typeid(T)] = sizeof(T);
v[&typeid(const T)] = sizeof(T);
v[&typeid(T*)] = sizeof(T);
v[&typeid(const T*)] = sizeof(T);
}
template <class T>
static int getSize (const T& x)
{
const type_info* id = &typeid(x);
if( v.find(id) == v.end() ){
throw ClassNotFoundException();
}
return v[id];
}
template <class T>
static int getSize (T* x)
{
return getSize(*x);
}
template <class T>
static int getSize (const T* x)
{
return getSize(*x);
}
protected:
static map<const type_info*, int> v;
};
map<const type_info*, int> Register::v;
class A
{
public:
A () : x () {}
virtual ~A () {}
protected:
int x;
};
class B
: public A
{
public:
B() : y () {}
virtual ~B () {}
protected:
int y;
};
int main ()
{
Register::reg<A>();
Register::reg<B>();
A* a = new B();
const A* b = new B();
cout << Register::getSize(a) << endl;
cout << Register::getSize(b) << endl;
}
Considering the nice answer of #Dennis Zickefoose, there's a case where you can implement multiple levels of inheritance which requires you neither to have virtual functions nor an intermediate class between each layer of inheritance and the added complexity.
And that's when all the intermediate (non-leaf) classes in the inheritance hierarchy are abstract classes, that is, they are not instantiated.
If that's the case, you can write the non-leaf abstract classes templated (again) on derived concrete types.
The example below demonstrates this:
template <class TDerived>
class Shape // Base
{
public:
float centerX;
float centerY;
int getSize()
{ return sizeof(TDerived); }
void demo()
{
std::cout
<< static_cast<TDerived*>(this)->getSize()
<< std::endl;
}
};
class Circle : public Shape<Circle>
{
public:
float radius;
};
class Square : public Shape<Square>
{
// other data...
};
template <class TDerived>
class Shape3D : public Shape<TDerived>
// Note that this class provides the underlying class the template argument
// it receives itself, and note that Shape3D is (at least conceptually)
// abstract because we can't directly instantiate it without providing it
// the concrete type we want, and because we shouldn't.
{
public:
float centerZ;
};
class Cube : public Shape3D<Cube>
{
// other data...
};
class Polyhedron : public Shape3D<Polyhedron>
{
public:
typedef float Point3D[3];
int numPoints;
Point3D points[MAX_POINTS];
int getSize() // override the polymorphic function
{ return sizeof(numPoints) + numPoints * sizeof(Point3D); }
// This is for demonstration only. In real cases, care must be taken about memory alignment issues to correctly determine the size of Polyhedron.
};
Sample usage:
Circle c;
c.demo();
Polyhedron p;
p.numPoints = 4;
p.demo();
I have two class hierarchies which have a 1:1 relationship: some normal classes A, B which have a common Root interface, and a WrapperRoot<T> interface with two concrete instantiations WrapperA<T> and WrapperB<T>. I am now looking to implement a function auto wrap<T>(Root& elem) -> unique_ptr<WrapperRoot<T>> that maps each normal class to its wrapper class.
The exact type of the wrappers is important as they will have virtual methods, and the exact type of the Root objects is not statically known.
Attempted solutions
My first idea was to declare a template virtual method in Root:
class Root {
...
public:
template<typename T>
virtual auto wrap() -> unique_ptr<WrapperRoot<T>> = 0;
}
which could then be implemented in the child classes as
class A : public Root {
...
template<typename T>
virtual auto wrap() -> unique_ptr<WrapperRoot<T>> override {
return make_unique<WrapperA<T>>();
}
}
As I was to find out, C++ does not allow templates for virtual methods. I did some further research and found the technique of type erasure, which allows us to break through this virtual vs. template dichtomy. Perhaps it might be possible to have each class select their wrapper type by passing in a visitor-like object that has erased the template parameter <T>? However, I am still fairly new to C++, and all my attempts to implement this have only moved the problem into another level, but not solved them.
This is especially frustrating since other languages which I am familiar with have no problem expressing this structure. E.g. in Java it is no problem to define a virtual method <T> WrapperRoot<T> wrap() { return new WrapperA<T>(); }, but that is because Java implements templates via reinterpreting casts. Java's implementation would be phrased in C++ as:
template<typename T>
WrapperRoot<T>* wrap() { return reinterpret_cast<WrapperRoot<T>*>(wrapper_impl()); }
virtual void* wrapper_impl() { return new WrapperA<void*>() }
However, I would like to work with the C++ type system rather than violating it by casting void pointers around.
Test Case
To phrase my problem unambiguously, I have created the below test case. Once wrap is implemented correctly, it should output this:
WrapperA
WrapperB
The main method should not be modified, but arbitrary methods, helper types, and an implementation for the wrap function may be added.
#include <iostream>
#include <memory>
using namespace std;
// the Root hierarchy
class Root {
public:
virtual ~Root() {}
};
class A : public Root {};
class B : public Root {};
// the Wrapper hierarchy
template<typename T>
class WrapperRoot {
public:
virtual ~WrapperRoot() {}
virtual T name() = 0;
};
template<typename T>
class WrapperA : public WrapperRoot<T> {
public:
virtual T name() { return T("WrapperA\n"); }
};
template<typename T>
class WrapperB : public WrapperRoot<T> {
public:
virtual T name() { return T("WrapperB\n"); }
};
// the "wrap" function I want to implement
template<typename T>
auto wrap(Root& ) -> unique_ptr<WrapperRoot<T>>;
// util
template<typename T, typename... Args>
auto make_unique(Args... args) -> unique_ptr<T> {
return unique_ptr<T>(new T(forward<Args>(args)...));
}
int main() {
unique_ptr<Root> a = make_unique<A>();
unique_ptr<Root> b = make_unique<B>();
cout << wrap<string>(*a)->name()
<< wrap<string>(*b)->name();
}
How can I make this work? Or do I need to resort to type-violating hacks?
The simplest way to get this to work would just be dynamic_casting the Root& to work out what the runtime type of it is:
template<typename T>
auto wrap(Root& root) -> unique_ptr<WrapperRoot<T>>
{
if (dynamic_cast<A*>(&root)) {
//root is an A, return a WrapperA
return make_unique<WrapperA<T>>();
}
else if (dynamic_cast<B*>(&root)) {
//root is a B, return a WrapperB
return make_unique<WrapperB<T>>();
}
throw std::runtime_error("No wrapper for that type");
}
Demo
As it turns out, this can be solved with type erasure, the Visitor Pattern, and a bit of indirection. The solution is clean, and does not require us to re-implement dynamic dispatch inside the wrap function.
The core idea is to introduce a WrapperSelector visitor interface:
class WrapperSelector {
public:
virtual auto visit(A&) -> void = 0;
virtual auto visit(B&) -> void = 0;
};
The Root hierarchy needs to be modified a bit to accept this visitor, and to perform the double dispatch:
class Root {
public:
virtual ~Root() {}
virtual auto accept(WrapperSelector&) -> void = 0;
};
class A : public Root {
public:
virtual auto accept(WrapperSelector& wrapper) -> void {
wrapper.visit(*this);
}
};
class B : public Root {
public:
virtual auto accept(WrapperSelector& wrapper) -> void {
wrapper.visit(*this);
}
};
So far, this is the bog-standard Visitor Pattern in C++. What we now do is introduce a templated class WrapperSelectorImpl<T> : public WrapperSelector. Since it is templated but only used through the un-templated interface, this implements type erasure. Internally, we construct this WrapperSelectorImpl as a container for a borrowed WrapperRoot<T> pointer, into which we write the selected wrapper. After the accept/visit sequence has ended, that pointer will be filled with the wrapper, so no virtual method needs to return a template-parameterized type. Also, the accept method does nothing but select the corresponding visit method, so the types in the Root hierarchy don't need to know about the WrapperRoot hierarchy – a concrete WrapperSelector will handle this mapping.
template<typename T>
class WrapperSelectorImpl : public WrapperSelector {
unique_ptr<WrapperRoot<T>>& _wrapper;
public:
explicit WrapperSelectorImpl(unique_ptr<WrapperRoot<T>>& wrapper)
: _wrapper(wrapper)
{}
virtual auto visit(A&) -> void override {
_wrapper = make_unique<WrapperA<T>>();
}
virtual auto visit(B&) -> void override {
_wrapper = make_unique<WrapperB<T>>();
}
};
Our wrap function must now set up a pointer, a WrapperSelectorImpl which borrows that pointer, let the given object in the Root hierarchy select the wrapper through the WrapperSelector, and return the now-populated pointer:
template<typename T>
auto wrap(Root& obj) -> unique_ptr<WrapperRoot<T>> {
unique_ptr<WrapperRoot<T>> wrapper;
WrapperSelectorImpl<T> wrapper_selector(wrapper);
obj.accept(wrapper_selector);
return wrapper;
}
Generalization
The above technique can be used to implement arbitrary templated virtual methods, or the visitor pattern with arbitrary return types. The prerequisites for this is minimal support for the Visitor Pattern`:
some Subject class or class hierarchy with a virtual void accept(SubjectVisitor& v) { v.visit(*this); }.
some SubjectVisitor interface with virtual void visit(S&) = 0 methods for each class S in the Subject class hierarchy.
Now assume we wish to implement a method with the following pseudo-signature in the Subject hierarchy:
class Subject {
...
template<typename R, typename T, typename... Args>
virtual R frobnicate(Args... args) = 0;
}
We can then use the following steps to implement this:
First, we create a wrapper function that exposes the public interface of our dispatching logic. This might be a non-virtual templated method in Subject, or a free function. The internals are the same as in the above example: Set-up of the return value, set-up of the visitor (borrowing a reference to the return value), doing the dispatch, and returning the value.
Since this is so general, we can pack this into a reusable templated function:
// most general implementation
template<typename ReturnType, typename Subject, typename Visitor, typename... Args>
auto manage_visitor(Subject& subject, Args... args) -> ReturnType {
ReturnType return_value;
Visitor visitor(return_value, std::forward(args)...);
subject.accept(visitor);
return return_value;
}
class Subject {
...
template<typename R, typename T, typename... Args>
R frobnicate(Args... args) {
return manage_visitor<R, Subject, ConcreteSubjectVisitor<R, T>>(*this, std::forward(args)...);
}
};
Note that this assumes the return value to be default-constructible. If this is not the case, substituting unique_ptr<ReturnType> for ReturnType could be a solution.
We now have to provide a class ConcreteSubjectVisitor : public SubjectVisitor that provides the actual implementation.
template<typename ReturnType, typename T>
class ConcreteSubjectVisitor : public SubjectVisitor {
ReturnType& return_value;
ArgType something;
public:
ConcreteSubjectVisitor(ReturnType& ret, ArgType& other_arg) : return_value(ret), something(other_arg) {}
virtual void visit(S1&) override { ... }
virtual void visit(S2&) override { ... }
...
};
The only thing which matters is that it can write to the return value. Note that the visitor can take additional arguments through the constructor, which makes it somewhat related to the std::bind function or to constructing a lambda. The visit definitions then contain the actual code, which has access to all type parameters of the visitor, and all constructor arguments of the visitor.
Open problems:
handling of return types that are not default-constructible (pointers or custom defaults)
specialization for void return type (problem decays to “normal” visitor pattern)
generalization to full multi-methods (trivial if method is in curried form)
providing a convenient interface
const-correctness (must be applied on a per-visitor basis, Subject::accept can be provided as const and non-const).
I tried to create an SSCE, because this usually also helps to find an issue early on. However, I can't seem to find a solution for this, so I would like to know if it is possible to define an argument which is an unspecified template class pointer.
I have an interface defined, and a parser class, which should handle the implementation details for xerces (like transcoding and all this overhead). The interface class would be designed to create the objects from the (SAX)parser, but without having to deal with the xerces library.
In Java I know I could use an unspecified generic type argument like this:
class Parser
{
public Parser(IGenericInterface<?> oImpl) {};
}
And basically I'm would like to know how this can be done in C++. In the below example I get a compiler error on the line declaring the interface variable because it is missing the type. But of course in the class declaration the type is unknown and should get assigned during runtime as shown in main.
#include <iostream>
#include <string>
template <class T>
class IGenericInterface
{
public:
IGenericInterface() {};
virtual ~IGenericInterface() {};
virtual T *createInstance(void) = 0;
};
template <class T>
class Implementation : public IGenericInterface<T>
{
public:
Implementation() {};
virtual ~Implementation() {};
T *createInstance(void)
{
T * t = new T;
return t;
}
};
class Parser
{
public:
Parser(IGenericInterface *oImpl) { mImpl = oImpl; };
virtual ~Parser() { delete mImpl; };
void doSomething(void) { do whatrever is needed; t = createInstance(); };
private:
IGenericInterface *mImpl;
};
int main()
{
Parser *p = new Parser(new Implementation<int>());
sleep(3);
return 0;
}
So how do I have to define the Parser constructor to make it pass an arbitrary interface argument?
C++ is a static language, so any types must be resolved at compile time. Hence, what you are doing in java cannot be done in the same way in C++. Instead, you use either dynamic polymorphism (using inheritance) or "static polymorphism", using templates (resolved at compile time) with CRTP.
Mixing static and dynamic polymorphism is a no go (exemptions might apply)
template <class T>
class IGenericInterface
{
public:
IGenericInterface() {};
virtual ~IGenericInterface() {};
virtual T *createInstance(void) = 0;
};
And your use of pointers is a nightmare.
Since apparently a generic like in Java can not be implemented in C++, I found a different solution which also allows me to keep the details of the parser separated.
The functions that should have been in the Interface class are now moved to the parser class as virtual abstract functions. The I can define a template which derives from the parser, thus be forced to implement the virtual functions, which basically is what I wanted.
The pattern looks like this now:
template <class T>
class ISerialization
{
public:
virtual ~ISerialization(void) {};
public:
virtual std::string serialize(void) = 0;
virtual bool deserialize(std::vector<T *> &oObjects, std::string const &oSerialized) = 0;
};
class parser
{
void parsing(void) { abstract_function(); }
virtual void abstract_function() = 0;
};
class implementation : public ISerialization<Task>, public parser
{
std::string serialize(void) {};
bool deserialize(std::vector<T *> &oObjects, std::string const &oSerialized) {};
void abstract_function() { specific implementation goes here};
};
Is it possible to find the size of a derived class object using a base class pointer, when you don't know the derived type.
Thank you.
There's no direct way, but you can write a virtual size() method child classes can implement. An intermediary templates class can automate the leg work.
struct base {
virtual size_t size() const =0;
virtual ~base() { }
};
template<typename T>
struct intermediate : base {
virtual size_t size() const { return sizeof(T); }
};
struct derived : intermediate<derived>
{ };
This does require your hierarchy be polymorphic... however, requesting behavior based on the dynamic type of an object rather than its static type is part of the definition of polymorphic behavior. So this won't add a v-table to the average use case, since at the very least you probably already have a virtual destructor.
This particular implementation does limit your inheritance tree to a single level without getting into multiple inheritance [ie, a type derived from derived will not get its own override of size]. There is a slightly more complex variant that gets around that.
struct base { /*as before */ };
template<typename Derived, typename Base>
struct intermediate : Base {
virtual size_t size() const { return sizeof(Derived); }
};
struct derived : intermediate<derived, base>
{ };
struct further_derived : intermediate<further_derived, derived>
{ };
Basically, this inserts an intermediate in between each actual layer of your hierarchy, each overriding size with the appropriate behavior, and deriving from the actual base type. Repeat ad nauseum.
//what you want
base >> derived
>> more_deriveder
>> most_derivedest
//what you get
base >> intermediate<derived, base>
>> derived >> intermediate<more_deriveder, derived>
>> more_deriveder >> intermediate<most_derivedest, more_deriveder>
>> most_derivedest
Several mixin-type libraries make use of such a scheme, such that the mixins can be added to an existing hierarchy without introducing multiple inheritance. Personally, I rarely use more than a single level of inheritance, so I don't bother with the added complexity, but your mileage may vary.
I don't think it can be done, because sizeof works on compile time types. You could define a virtual Size function in the base class and override it for each derived class.
Due to lack of reflection in C++, this is not generally possible with arbitrary classes at a whim. There are some workarounds however. You can write a virtual size() method as others have suggested. You can also use the Curiously Recurring Template Pattern, aka inheriting from Register<T> as well but I wouldn't recommend it, vtable costs 4 bytes per object, subclasses of T report incorrect size and correcting it results in multiple inheritance.
The best way would be to use a class to register, store and query dynamic size information, without modifying the class you want to query:
EDIT: As it turns out, due to the inconsistent semantics of typeid, it still needs classes with vtables, see the comments.
#include <cstddef>
#include <exception>
#include <iostream>
#include <map>
#include <typeinfo>
using namespace std;
class ClassNotFoundException
: public exception
{};
class Register
{
public:
template <class T>
static void reg (T* = NULL)
{
// could add other qualifiers
v[&typeid(T)] = sizeof(T);
v[&typeid(const T)] = sizeof(T);
v[&typeid(T*)] = sizeof(T);
v[&typeid(const T*)] = sizeof(T);
}
template <class T>
static int getSize (const T& x)
{
const type_info* id = &typeid(x);
if( v.find(id) == v.end() ){
throw ClassNotFoundException();
}
return v[id];
}
template <class T>
static int getSize (T* x)
{
return getSize(*x);
}
template <class T>
static int getSize (const T* x)
{
return getSize(*x);
}
protected:
static map<const type_info*, int> v;
};
map<const type_info*, int> Register::v;
class A
{
public:
A () : x () {}
virtual ~A () {}
protected:
int x;
};
class B
: public A
{
public:
B() : y () {}
virtual ~B () {}
protected:
int y;
};
int main ()
{
Register::reg<A>();
Register::reg<B>();
A* a = new B();
const A* b = new B();
cout << Register::getSize(a) << endl;
cout << Register::getSize(b) << endl;
}
Considering the nice answer of #Dennis Zickefoose, there's a case where you can implement multiple levels of inheritance which requires you neither to have virtual functions nor an intermediate class between each layer of inheritance and the added complexity.
And that's when all the intermediate (non-leaf) classes in the inheritance hierarchy are abstract classes, that is, they are not instantiated.
If that's the case, you can write the non-leaf abstract classes templated (again) on derived concrete types.
The example below demonstrates this:
template <class TDerived>
class Shape // Base
{
public:
float centerX;
float centerY;
int getSize()
{ return sizeof(TDerived); }
void demo()
{
std::cout
<< static_cast<TDerived*>(this)->getSize()
<< std::endl;
}
};
class Circle : public Shape<Circle>
{
public:
float radius;
};
class Square : public Shape<Square>
{
// other data...
};
template <class TDerived>
class Shape3D : public Shape<TDerived>
// Note that this class provides the underlying class the template argument
// it receives itself, and note that Shape3D is (at least conceptually)
// abstract because we can't directly instantiate it without providing it
// the concrete type we want, and because we shouldn't.
{
public:
float centerZ;
};
class Cube : public Shape3D<Cube>
{
// other data...
};
class Polyhedron : public Shape3D<Polyhedron>
{
public:
typedef float Point3D[3];
int numPoints;
Point3D points[MAX_POINTS];
int getSize() // override the polymorphic function
{ return sizeof(numPoints) + numPoints * sizeof(Point3D); }
// This is for demonstration only. In real cases, care must be taken about memory alignment issues to correctly determine the size of Polyhedron.
};
Sample usage:
Circle c;
c.demo();
Polyhedron p;
p.numPoints = 4;
p.demo();
I have code like this:
class RetInterface {...}
class Ret1: public RetInterface {...}
class AInterface
{
public:
virtual boost::shared_ptr<RetInterface> get_r() const = 0;
...
};
class A1: public AInterface
{
public:
boost::shared_ptr<Ret1> get_r() const {...}
...
};
This code does not compile.
In visual studio it raises
C2555: overriding virtual function return type differs and is not
covariant
If I do not use boost::shared_ptr but return raw pointers, the code compiles (I understand this is due to covariant return types in C++). I can see the problem is because boost::shared_ptr of Ret1 is not derived from boost::shared_ptr of RetInterface. But I want to return boost::shared_ptr of Ret1 for use in other classes, else I must cast the returned value after the return.
Am I doing something wrong?
If not, why is the language like this - it should be extensible to handle conversion between smart pointers in this scenario? Is there a desirable workaround?
Firstly, this is indeed how it works in C++: the return type of a virtual function in a derived class must be the same as in the base class. There is the special exception that a function that returns a reference/pointer to some class X can be overridden by a function that returns a reference/pointer to a class that derives from X, but as you note this doesn't allow for smart pointers (such as shared_ptr), just for plain pointers.
If your interface RetInterface is sufficiently comprehensive, then you won't need to know the actual returned type in the calling code. In general it doesn't make sense anyway: the reason get_r is a virtual function in the first place is because you will be calling it through a pointer or reference to the base class AInterface, in which case you can't know what type the derived class would return. If you are calling this with an actual A1 reference, you can just create a separate get_r1 function in A1 that does what you need.
class A1: public AInterface
{
public:
boost::shared_ptr<RetInterface> get_r() const
{
return get_r1();
}
boost::shared_ptr<Ret1> get_r1() const {...}
...
};
Alternatively, you can use the visitor pattern or something like my Dynamic Double Dispatch technique to pass a callback in to the returned object which can then invoke the callback with the correct type.
There is a neat solution posted in this blog post (from Raoul Borges)
An excerpt of the bit prior to adding support for mulitple inheritance and abstract methods is:
template <typename Derived, typename Base>
class clone_inherit<Derived, Base> : public Base
{
public:
std::unique_ptr<Derived> clone() const
{
return std::unique_ptr<Derived>(static_cast<Derived *>(this->clone_impl()));
}
private:
virtual clone_inherit * clone_impl() const override
{
return new Derived(*this);
}
};
class concrete: public clone_inherit<concrete, cloneable>
{
};
int main()
{
std::unique_ptr<concrete> c = std::make_unique<concrete>();
std::unique_ptr<concrete> cc = c->clone();
cloneable * p = c.get();
std::unique_ptr<clonable> pp = p->clone();
}
I would encourage reading the full article. Its simply written and well explained.
You can't change return types (for non-pointer, non-reference return types) when overloading methods in C++. A1::get_r must return a boost::shared_ptr<RetInterface>.
Anthony Williams has a nice comprehensive answer.
What about this solution:
template<typename Derived, typename Base>
class SharedCovariant : public shared_ptr<Base>
{
public:
typedef Base BaseOf;
SharedCovariant(shared_ptr<Base> & container) :
shared_ptr<Base>(container)
{
}
shared_ptr<Derived> operator ->()
{
return boost::dynamic_pointer_cast<Derived>(*this);
}
};
e.g:
struct A {};
struct B : A {};
struct Test
{
shared_ptr<A> get() {return a_; }
shared_ptr<A> a_;
};
typedef SharedCovariant<B,A> SharedBFromA;
struct TestDerived : Test
{
SharedBFromA get() { return a_; }
};
Here is my attempt :
template<class T>
class Child : public T
{
public:
typedef T Parent;
};
template<typename _T>
class has_parent
{
private:
typedef char One;
typedef struct { char array[2]; } Two;
template<typename _C>
static One test(typename _C::Parent *);
template<typename _C>
static Two test(...);
public:
enum { value = (sizeof(test<_T>(nullptr)) == sizeof(One)) };
};
class A
{
public :
virtual void print() = 0;
};
class B : public Child<A>
{
public:
void print() override
{
printf("toto \n");
}
};
template<class T, bool hasParent = has_parent<T>::value>
class ICovariantSharedPtr;
template<class T>
class ICovariantSharedPtr<T, true> : public ICovariantSharedPtr<typename T::Parent>
{
public:
T * get() override = 0;
};
template<class T>
class ICovariantSharedPtr<T, false>
{
public:
virtual T * get() = 0;
};
template<class T>
class CovariantSharedPtr : public ICovariantSharedPtr<T>
{
public:
CovariantSharedPtr(){}
CovariantSharedPtr(std::shared_ptr<T> a_ptr) : m_ptr(std::move(a_ptr)){}
T * get() final
{
return m_ptr.get();
}
private:
std::shared_ptr<T> m_ptr;
};
And a little example :
class UseA
{
public:
virtual ICovariantSharedPtr<A> & GetPtr() = 0;
};
class UseB : public UseA
{
public:
CovariantSharedPtr<B> & GetPtr() final
{
return m_ptrB;
}
private:
CovariantSharedPtr<B> m_ptrB = std::make_shared<B>();
};
int _tmain(int argc, _TCHAR* argv[])
{
UseB b;
UseA & a = b;
a.GetPtr().get()->print();
}
Explanations :
This solution implies meta-progamming and to modify the classes used in covariant smart pointers.
The simple template struct Child is here to bind the type Parent and inheritance. Any class inheriting from Child<T> will inherit from T and define T as Parent. The classes used in covariant smart pointers needs this type to be defined.
The class has_parent is used to detect at compile time if a class defines the type Parent or not. This part is not mine, I used the same code as to detect if a method exists (see here)
As we want covariance with smart pointers, we want our smart pointers to mimic the existing class architecture. It's easier to explain how it works in the example.
When a CovariantSharedPtr<B> is defined, it inherits from ICovariantSharedPtr<B>, which is interpreted as ICovariantSharedPtr<B, has_parent<B>::value>. As B inherits from Child<A>, has_parent<B>::value is true, so ICovariantSharedPtr<B> is ICovariantSharedPtr<B, true> and inherits from ICovariantSharedPtr<B::Parent> which is ICovariantSharedPtr<A>. As A has no Parent defined, has_parent<A>::value is false, ICovariantSharedPtr<A> is ICovariantSharedPtr<A, false> and inherits from nothing.
The main point is as Binherits from A, we have ICovariantSharedPtr<B>inheriting from ICovariantSharedPtr<A>. So any method returning a pointer or a reference on ICovariantSharedPtr<A> can be overloaded by a method returning the same on ICovariantSharedPtr<B>.
Mr Fooz answered part 1 of your question. Part 2, it works this way because the compiler doesn't know if it will be calling AInterface::get_r or A1::get_r at compile time - it needs to know what return value it's going to get, so it insists on both methods returning the same type. This is part of the C++ specification.
For the workaround, if A1::get_r returns a pointer to RetInterface, the virtual methods in RetInterface will still work as expected, and the proper object will be deleted when the pointer is destroyed. There's no need for different return types.
maybe you could use an out parameter to get around "covariance with returned boost shared_ptrs.
void get_r_to(boost::shared_ptr<RetInterface>& ) ...
since I suspect a caller can drop in a more refined shared_ptr type as argument.