C++ avoid call to abstract base class's constructor - c++

Currently, I am building a library in C++ (using C++11 standards), and I am stuck on trying to figure out how to make my design more practical. I have the following abstract class E
template<typename K>
class E
{
public:
virtual ~E() {};
virtual void init() = 0;
virtual void insert(const K& k) = 0;
virtual size_t count() const = 0;
virtual void copy(const E<Key>& x) = 0;
};
which I want to restrict users from instantiating it (i.e., be an interface). E has two sub-classes that implement the corresponding methods:
template<typename K>
class EOne : public E<K>
{
public:
EOne() {}
EOne(const EOne& x) {...}
void init() override
{
...
}
void insert(const K& v) override
{
...
}
size_t count() const override
{
...
}
void copy(const E<K>& o) override
{
...
}
private:
// some private fields
};
and ETwo : public E<K>, which is similar to EOne. Also, there is a different class J, which has a member std::vector<E<K>> that needs to be instantiated during construction:
template<typename K>
class J
{
public:
J(size_t n, const E<K>& e) : v(n, e)
{}
private:
std::vector<E<K>> v;
}
In essence, by getting a constant reference for a E<K> object, I want J's constructor to use the reference to instantiate all n objects of v using e as a template (i.e., call the copy constructor). As you can imagine, my goal is to have e be an object of either EOne<K> or ETwo<K>. For instance, I would make a call to J<K>::J(size_t n, const E<K>& e) the following way:
int main(int argc, char** argv)
{
EOne<std::string> e;
J<std::string> j(10, e); // populate v with 10 copies of e
...
}
However, the above does not compile and the compiler complains that I cannot instantiate abstract class (I am using vc++ but I believe I will get the same error on other compilers as well). Therefore, my question has to do on how I can overcome this problem? Do you have any suggestions on how I can make my design more practical.
Thank you

There is more than one approach to this. What follows is the most complex reasonable one. It requires lots of work in the type definitions, but leads to the cleanest "client" code that uses these types.
It is time to learn how to make a type regular.
An instance of a regular type behaves like a value. C++ algorithms and container work far better with regular types than it does with abstract types.
template<class K>
class E_interface {
public:
virtual ~E_interface() {};
virtual void init() = 0;
virtual void insert(const K& k) = 0;
virtual size_t count() const = 0;
virtual void copy_from(const E_interface& x) = 0;
std::unique_ptr<E_interface> clone() const = 0;
};
this is basically your E, except I added clone().
template<class T, class D=std::default_delete<D>, class Base=std::unique_ptr<T>>
struct clone_ptr:Base {
using Base::Base;
clone_ptr(Base&& b):Base(std::move(b)) {}
clone_ptr()=default;
clone_ptr(clone_ptr&&o)=default;
clone_ptr(clone_ptr const& o):
clone_ptr(
o?clone_ptr(o->clone()):clone_ptr()
)
{}
clone_ptr& operator=(clone_ptr&&o)=default;
clone_ptr& operator=(clone_ptr const&o) {
if (*this && o) {
get()->copy_from(*o.get());
} else {
clone_ptr tmp(o);
*this = std::move(tmp);
}
return *this;
}
};
The clone_ptr is a smart pointer that is a unique_ptr that knows how to copy itself by calling clone() and copy_from on the stored object. It may have some typos.
Now we write our E:
template<class K>
class E {
clone_ptr<E_interface<K>> pImpl;
public:
E() = default;
E( std::unique_ptr<E_interface<K>> in ):pImpl(std::move(in)) {}
E( E const& )=default;
E( E && )=default;
E& operator=( E const& )=default;
E& operator=( E && )=default;
explicit operator bool() const { return (bool)pImpl; }
void init() { if (*this) pImpl->init(); }
void insert(const K& k) ( if (*this) pImpl->insert(k); }
size_t count() const { if (*this) pImpl->count(); else return 0; }
};
Our E<K> is now a value type. It can be stored in a vector, copied, moved, etc.
How do we do EOne and ETwo?
First, take your existing EOne and ETwo and call them EOne_impl and ETwo_impl. Implement a clone() function that does a return std::make_unique<EOne_impl>(*this); for EOne_impl and similar for ETwo_impl.
Then this helper:
template<class Impl, class K>
struct E_impl: E<K> {
using E<K>::E<K>;
E_impl() : E<K>( std::make_unique<Impl>() ) {}
template<class...Args>
E_impl(Args&&...args) : E<K>( std::make_unique<Impl>(std::forward<Args>(args)...) ) {}
};
gives us
template<class K>
using Eone = E_impl< Eone_impl, K >;
template<class K>
using Etwo = E_impl< Etwo_impl, K >;
and I believe your J and main code starts compiling and working as-is.
What we just did was create value-semantics E<K> type that contains a pImpl (pointer to implementation) pointing to a pure-virtual interface that knows how to copy itself, as well as the interface we want on an E<K>.
We then forwarded the interface of E<K> to the E_interface<K> for each method. We didn't expose copy_from or clone, as those become operator= and our copy constructor.
To implement E<K>, you first implement E_interface<K>. Then I wrote a helper to create a derived type from E<K> that implicitly uses that implementation.
Note that our E<K> is almost-never empty; not never-empty. This is more efficient and simpler, but can cause problems down the road.
E<K> becomes a polymorphic value-semantics type. This is a strange beast in some senses (as many languages don't support such a type), but in other senses it behaves exactly the way you'd want it to behave.
A similar solution in C# or Java would have the data stored in the vectors be fully garbage collected reference-semantics types, not value-semantics types.
This is similar to a std::vector<std::shared_ptr<E<K>> (with the note that shared pointers are not fully garbage collected). Also note that copies of the shared_ptr end up being pointing to the same object, not new copies of it.
A std::vector<value_ptr<E_interface<K>> would also be a reasonable solution and get rid of some of the gymnastics I did in my E<K> and E_impl<K>. In this case, you wouldn't rename E to E_interface. You'd initialize the vector with
J<std::string> j(10, std::make_unique<EOne<std::string>>(e))
or somesuch.
Part of your problem is you have to ask yourself "what does it mean to copy an E<K>". In C++ you get to answer this question yourself; depending on how you answer it, you may or may not be permitted to store it in a std::vector.

Since std::vector<E<K>> v; requires a static instantiation of class E, it will never compile (as you already noticed correctly). To make it work should use
std::vector<std::shared_ptr<E<K>>> v;
instead. It can store your objects EOne and ETwo dynamically while they can be referred with a pointed of type E. To add a new object to the vector you can use push_back:
v.push_back(std::make_shared<EOne<K>>{});
To cast between the types you can use dynamic and static cast functions for smart pointers e.g. std::dynamic_pointer_cast<>().

Related

Retrieve objects pointers of different type

Consider I have a bunch pointers to to different objects of different classes
class1* obj1;
class2* obj2;
class3* obj3;
and they all have one method getArray() which returns a vector for post processing.
if all of these pointers are stored in some sort of a list (a list of void pointers say)
while I am iterating the list is there a way to figure what type of a pointer cast can be used?
I understand this can be solved by class hierarchy and deriving the above classes from a single class. Since a lot of it is legacy code can something like what is mentioned be done?
Folly dynamic does not let me store pointers, thats one thing that is tried
If getArray() always has the same signature (or similar enough to cast to the same type) - what you could do is create a class hierarchy for a decorator of the duck-typed legacy objects/classes. You can use a template derived class of a non-template interface to wrap without too much typing work.
Something along these lines (with more defensive coding, possibly smart pointers to the legacy object, etc. etc.):
class IDecorator {
public:
virtual std::vector<ubyte> GetArray() = 0;
};
template<typename TLegacyType>
class TDecorator : public IDecorator {
public:
TDecorator(const TLegacyType *ip_legacy_object)
: mp_legacy_object(ip_legacy_object) {}
std::vector<ubyte> GetArray() override {
return mp_legacy_object->GetArray();
}
private:
const TLegacyType *mp_legacy_object;
};
template<class R, class Op>
struct any_ptr {
void* ptr=0;
R(*f)( void* ) = 0;
R operate() const { return f(ptr); }
explicit operator bool() const { return ptr; }
template<class T>
T* as() const { return static_cast<T*>(ptr); }
any_ptr(any_ptr const&)=default;
any_ptr& operator=(any_ptr const&)=default;
any_ptr()=default;
template<class T>
any_ptr(T* p_in):ptr(p_in),
f( [](void* ptr)->R{ return Op{}( ptr ); } )
{}
};
any_ptr supports storing any pointer that supports Op, where Op is a stateless function object type returning R.
struct get_array_t{
template<class T>
auto operator()(T* t)const{ return t->getArray(); }
};
using any_ptr_get_array = any_ptr< std::vector<int>, get_array_t >;
now any_ptr_get_array can store a pointer to any type that supports .getArray() that returns vector<int>.
To call getArray:
void test(any_ptr_get_array ptr){
if(ptr){
auto vec = ptr.operation();
}
}
This technique could be called manual type erasure using a template generated vtable.

Polymorphism and casting through struct with pointers

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.

std::unique_ptr, Default Copy Constructor, and Abstract Class

I have class representing a tree object that uses unique pointers, some nodes that make up the tree, and a function that constructs pointers to an abstract node class based on some arguments (It makes pointers to subclasses, since abstract node is abstract)
class AbstractNode
{
vector<unique_ptr<AbstractNode>> children;
public:
AbstractNode(arguments...);
// other stuff...
};
class Tree
{
unique_ptr<AbstractNode> baseNode;
// other stuff...
}
unique_ptr<AbstractNode> constructNode(AbstractNodeTypes type);
There are a variety of subclasses of abstractNode that will be contained in the tree. The subclasses provide different implementations for some virtual functions in that class.
I want to be able to copy my tree by creating a new set of nodes with the same class types that are distinct copies of the nodes in the original tree.
Here is the problem:
If I write my own copy constructor for the AbstractNode class that deep copies the children, I'll have to write copy constructors for all of the subclasses of AbstractNode, which seems annoying since the only thing that won't copy correctly are the children pointers. It will also be annoying to use copy constructors here because I will need to cast the children to the correct types before I call them, I think.
Is there some way I can get the compiler to let me use the default copy constructor to set up everything except for the children. It can leave those as null pointers or something? Then I can write a simpler function that just recursively adds children to copy a tree.
If that is impossible, is there any non-ugly solution to this problem that anyone knows of?
The typical way to solve this problem is to have a virtual clone function similar to what Kerrek SB describes in his answer. However I would not bother writing your own value_ptr class. It is simpler to just reuse std::unique_ptr as your question presents. It will require a non-default copy constructor in AbstractNode, but does not require explicit or unsafe casting:
class AbstractNode
{
std::vector<std::unique_ptr<AbstractNode>> children;
public:
AbstractNode() = default;
virtual ~AbstractNode() = default;
AbstractNode(AbstractNode const& an)
{
children.reserve(an.children.size());
for (auto const& child : an.children)
children.push_back(child->clone());
}
AbstractNode& operator=(AbstractNode const& an)
{
if (this != &an)
{
children.clear();
children.reserve(an.children.size());
for (auto const& child : an.children)
children.push_back(child->clone());
}
return *this;
}
AbstractNode(AbstractNode&&) = default;
AbstractNode& operator=(AbstractNode&&) = default;
// other stuff...
virtual
std::unique_ptr<AbstractNode>
clone() const = 0;
};
Now a ConcreteNode can be implemented. It must have a valid copy constructor which may be defaulted depending upon what data members ConcreteNode adds to the mix. And it must implement clone(), but that implementation is trivial:
class ConcreteNode
: public AbstractNode
{
public:
ConcreteNode() = default;
virtual ~ConcreteNode() = default;
ConcreteNode(ConcreteNode const&) = default;
ConcreteNode& operator=(ConcreteNode const&) = default;
ConcreteNode(ConcreteNode&&) = default;
ConcreteNode& operator=(ConcreteNode&&) = default;
// other stuff...
virtual
std::unique_ptr<AbstractNode>
clone() const override
{
return std::unique_ptr<AbstractNode>(new ConcreteNode(*this));
}
};
I suggest having clone return a unique_ptr instead of a raw pointer just to ensure that there is no chance that a new'd pointer is ever exposed without an owner.
For completeness I've also shown what the other special members would look like.
At first I was thinking that C++14's make_unique would be nice to use here. And it can be used here. But personally I think in this particular example it really doesn't carry its weight. Fwiw, here is what it would look like:
virtual
std::unique_ptr<AbstractNode>
clone() const override
{
return std::make_unique<ConcreteNode>(*this);
}
Using make_unique you have to first construct a unique_ptr<ConcreteNode>, and then rely on the implicit conversion from that to unique_ptr<AbstractNode>. This is correct, and the extra dance probably will get optimized away as soon as inlining is fully enabled. But the use of make_unique just seems like an unnecessary obfuscation here when what you really clearly need is a unique_ptr<AbstractNode> constructed with a new'd ConcreteNode*.
Instead of using unique_ptr, you may wish to roll your own implementation of a value_ptr. Those designs have been proposed regularly in the past, but until we have a standardized version, either roll your own or find an existing implementation.
It would look a bit like this:
template <typename T> struct value_ptr
{
T * ptr;
// provide access interface...
explicit value_ptr(T * p) noexcept : ptr(p) {}
~value_ptr() { delete ptr; }
value_ptr(value_ptr && rhs) noexcept : ptr(rhs.ptr)
{ rhs.ptr = nullptr; }
value_ptr(value_ptr const & rhs) : ptr(rhs.clone()) {}
value_ptr & operator=(value_ptr && rhs) noexcept
{
if (&rhs != this) { delete ptr; ptr = rhs.ptr; rhs.ptr = nullptr; }
return *this;
}
value_ptr & operator=(value_ptr const & rhs)
{
if (&rhs != this) { T * p = rhs.clone(); delete ptr; ptr = p; }
return *this;
}
};
You can build your tree from a set of clonable nodes.
struct AbstractNode
{
virtual ~AbstractNode() {}
virtual AbstractNode * clone() const = 0;
std::vector<value_ptr<AbstractNode>> children;
};
struct FooNode : AbstractNode
{
virtual FooNode * clone() const override { return new FooNode(this); }
// ...
};
Now your nodes are copyable automatically without the need for you to write any explicit copy constructors. All you need to do is to maintain discipline by overriding clone in every derived class.
The normal pattern for this is a virtual clone method through your hierarchy.
If that is impossible, is there any non-ugly solution to this problem that anyone knows of?
You can also use template instantiation of a clone function based on copy constructors. Here's a solution I use in a web server I'm writing (pet project):
#pragma once
#include <memory>
#include <cassert>
#include <functional>
#include <stdexcept>
#include <vector>
namespace stdex {
inline namespace details {
/// #brief Deep copy construct from (Specialized&)*src
///
/// #retval nullptr if src is nullptr
/// #retval Specialized clone of *src
///
/// #note Undefined behavior src does not point to a Specialized*
template<typename Base, typename Specialized>
Base* polymorphic_clone (const Base* src) {
static_assert(std::is_base_of<Base, Specialized>::value,
"Specialized is not a specialization of Base");
if (src == nullptr)
return nullptr;
return new Specialized{ static_cast<const Specialized&>(*src) };
}
}
/// #brief polymorphic reference interface over a base class
///
/// Respects polymorphic behavior of class ref.
/// Instances have deep copy semantics (clone) and
/// "[const] Base&" interface
///
/// #note Not regular: no trivial way to implement non-intrusive equality
///
/// #note safe to use with standard containers
template<typename Base>
class polymorphic final
{
public:
/// Functor capable to convert a Base* to it's specialized type
/// and clone it (intrusive implementation can be used)
typedef std::function<Base* (const Base*)> clone_functor;
/// #brief construct (takes ownership of ptr)
template<typename Specialized, typename CloneSpecialized>
polymorphic(Specialized* ptr, CloneSpecialized functor) noexcept
: instance_{ptr}, clone_{std::move(functor)}
{
static_assert(std::is_base_of<Base, Specialized>::value,
"Specialized is not a specialization of Base");
static_assert(
std::is_constructible<clone_functor, CloneSpecialized>::value,
"CloneSpecialized is not valid for a clone functor");
}
// not implemented: UB cloning in case client provides specialized ptr
// polymorphic(Base* ptr);
polymorphic()
: polymorphic{ nullptr, clone_functor{} }
{
}
polymorphic(polymorphic&&) = default;
polymorphic(const polymorphic& other)
: polymorphic{std::move(other.clone())}
{
}
polymorphic& operator=(polymorphic other)
{
std::swap(instance_, other.instance_);
std::swap(clone_, other.clone_);
return *this;
}
~polymorphic() = default;
/// #brief Cast to contained type
/// #pre instance not moved
/// #pre *this initialized with valid instance
operator Base&() const
{
assert(instance_.get());
return *instance_.get();
}
/// #brief Cast to contained type
/// #pre instance not moved
/// #pre *this initialized with valid instance
operator const Base&() const
{
assert(instance_.get());
return *instance_.get();
}
private:
polymorphic clone() const
{
return polymorphic{
clone_(instance_.get()), clone_functor{clone_}
};
}
std::unique_ptr<Base> instance_;
clone_functor clone_;
};
template<typename Base, typename Specialized, typename CF>
polymorphic<Base> to_polymorphic(Specialized&& temp, CF functor)
{
static_assert(std::is_base_of<Base, Specialized>::value,
"Specialized is not a specialization of Base");
typedef typename polymorphic<Base>::clone_functor clone_functor;
auto ptr_instance = std::unique_ptr<Base>{
new Specialized{std::move(temp)}
};
auto clone_instance = clone_functor{std::move(functor)};
return polymorphic<Base>{ptr_instance.release(), clone_instance};
}
template<typename Base, typename Specialized>
polymorphic<Base> to_polymorphic(Specialized&& temp)
{
static_assert(std::is_base_of<Base, Specialized>::value,
"Specialized is not a specialization of Base");
return to_polymorphic<Base,Specialized>(
std::move(temp), details::polymorphic_clone<Base,Specialized>
);
}
template<typename Base, typename Specialized, typename ...Args>
polymorphic<Base> to_polymorphic(Args ...args)
{
static_assert(std::is_constructible<Specialized, Args...>::value,
"Cannot instantiate Specialized from arguments");
return to_polymorphic<Base,Specialized>(
std::move(Specialized{std::forward<Args...>(args...)}));
}
template<typename Base> using polymorphic_vector =
std::vector<polymorphic<Base>>;
template<typename Base, typename ...Args>
polymorphic_vector<Base> to_polymorphic_vector(Args&& ...args)
{
return polymorphic_vector<Base>{to_polymorphic<Base>(args)...};
}
} // stdex
Example use:
stdex::polymorphic_vector<view> views = // explicit type for clarity
stdex::to_polymorphic_vector(
echo_view{"/echo"}, // class echo_view : public view
directory_view{"/static_files"} // class directory_view : public view
);
for(auto& v: views)
if(v.matches(reuqest.url())) // bool view::matches(...);
auto response = view.handle(request); // virtual view::handle(...) = 0;
Limitations of this:
If you use multiple inheritance DO NOT USE stdex::details::polymorphic_clone. Write an implementation based on dynamic_cast instead, and use to_polymorphic(Specialized&& temp, CF functor).
If you want to use the default behavior for part of your class, and only enhance it with non-standard behavior for the rest, consider functionally and organisationally splitting your class:
Put all those elements where you want the default-behavior into their own sub-object (inherited or composited), so you can easily use the default-special-function for them, and add the rest outside that sub-object.
Implementation left as an exercise for the interested reader.

Interfaces and covariance problem

I have a particular class that stores a piece of data, which implements an interface:
template<typename T>
class MyContainer : public Container<T> {
class Something : public IInterface {
public:
// implement *, ->, and ++ here but how?
private:
T x;
};
// implement begin and end here, but how?
private:
Something* data; // data holds the array of Somethings so that references to them can be returned from begin() and end() to items in this array so the interface will work, but this makes the problem described below
};
And I have an array of Somethings.
I have the need for Something to implement an interface class (IInterface in the example) which:
Contains pure virtual member functions which return something such that *retval returns a reference to the x member, retval-> returns the address of x, and ++retval makes retval refer to the next Something in the array.
The things that the pure virtual members return can be inherited from and returned by the implementation of the members
container[i] (where container is the array holding the Something objects) always returns something such that *retval always returns a reference to the same T for the same i.
Right now, the interface looks like this:
template<typename T>
class Container {
class IInterface {
public:
virtual T& operator*() = 0;
virtual T* operator->() = 0;
virtual IInterface& operator++(); // this is the problem
};
// returning a reference right now to support covariance, so subclasses can
// derive from Container and then have a member class derive from IInterface
// and override these to return their derived class, but this has a problem
virtual IInterface& begin() = 0;
virtual IInterface& end() = 0;
};
My current solution (have the virtual methods return an IInterface& and return a Something& in the implementation) has no problem with the requirements, except for the ++retval requirement. Because the Something is directly tied to the object it holds and can't point to a T with a pointer, there's no way that I can find to get ++ to make the variable refer to the next Something in the array.
If it helps to know, this is an iterator type system. I would have made it with the STL style iterators (where you just have an array of T) that are passed around by value and hold pointers to the values they represent, but that would break the interface because only references and pointers are covariant, and the objects already have to exist somewhere else already (in my code they're in the array) so you don't return a reference to a local object.
The purpose of this setup is so that one can write functions that take a Container& and iterate the container without knowing what type of container it is:
void iterate(Container<int>& somecontainer) {
Container<int>::IIterator i = somecontainer.begin(); // right now this would return a reference, but it doesn't/can't work that way
while (i != somecontainer.end()) {
doSomething(*i);
++i; // this is the problem
}
}
It's kind of difficult for me to describe, don't hesitate to let me know if you need more information.
What you are trying to do is called type erasure. Basically you want to provide a value type (which is the same across the whole inheritance hierarchy) that wraps the particular iterator type and offers a uniform dynamic interface.
Type erasure is usually implemented with a non-virtual class (the type erased) that stores a pointer to a virtual base class that implements the erasure, from which you derive different types that wrap each particular iterator. The static class would offer templated constructor/assignment operators that would dynamically instantiate an object of the derived type and store the pointer internally. Then you only need to implement the set of operations as dispatch to the internal object.
For the simplest form of type erasure possible, you can take a look at the implementation of boost::any (documentation is here)
Sketch:
namespace detail {
template<typename T>
struct any_iterator_base {
virtual T* operator->() = 0; // Correct implementation of operator-> is tough!
virtual T& operator*() = 0;
virtual any_iterator_base& operator++() = 0;
};
template <typename T, typename Iterator>
class any_iterator_impl : any_iterator_base {
Iterator it;
public:
any_iterator_impl( Iterator it ) : it(it) {}
virtual T& operator*() {
return *it;
}
any_iterator_impl& operator++() {
++it;
return *this;
}
};
}
template <typename T>
class any_iterator {
detail::any_iterator_base<T>* it;
public:
template <typename Iterator>
any_iterator( Iterator it ) : it( new detail::any_iterator_impl<T,Iterator>(it) ) {}
~any_iterator() {
delete it;
}
// implement other constructors, including copy construction
// implement assignment!!! (Rule of the Three)
T& operator*() {
return *it; // virtual dispatch
}
};
The actual implementation becomes really messy. You need to provide different versions of the iterator for the different iterator types in the standard, and the detail of the implementation of the operators might not be trivial either. In particular operator-> is applied iteratively until a raw pointer is obtained, and you want to make sure that your type erased behavior does not break that invariant or document how you break it (i.e. limitations on the type T that your adaptor can wrap)
For extended reading:
- On the Tension Between Object-Oriented and Generic Programming in C++
- any_iterator: Implementing Erasure for C++ iterators
- adobe any_iterator ,
I would suggest a look at the Visitor pattern.
Other than that, what you want is a value type that will be imbued with polymorphic behavior. There is a much simpler solution than James' using your IInterface.
class IInterface
{
virtual ~IInterface() {}
virtual void next() = 0;
virtual void previous() = 0;
virtual T* pointer() const = 0;
virtual std::unique_ptr<IInterface> clone() const = 0;
};
std::unique_ptr<IInterface> clone(std::unique_ptr<IInterface> const& rhs) {
if (!rhs) { return std::unique_ptr<IInterface>(); }
return rhs->clone();
}
class Iterator
{
friend class Container;
public:
Iterator(): _impl() {}
// Implement deep copy
Iterator(Iterator const& rhs): _impl(clone(rhs._impl)) {}
Iterator& operator=(Iterator rhs) { swap(*this, rhs); return *this; }
friend void swap(Iterator& lhs, Iterator& rhs) {
swap(lhs._impl, rhs._impl);
}
Iterator& operator++() { assert(_impl); _impl->next(); return *this; }
Iterator& operator--() { assert(_impl); _impl->previous(); return *this; }
Iterator operator++(int); // usual
Iterator operator--(int); // usual
T* operator->() const { assert(_impl); return _impl->pointer(); }
T& operator*() const { assert(_impl); return *_impl->pointer(); }
private:
Iterator(std::unique_ptr<IInterface> impl): _impl(impl) {}
std::unique_ptr<IInterface> _impl;
};
And finally, the Container class will propose:
protected:
virtual std::unique_ptr<IInterface> make_begin() = 0;
virtual std::unique_ptr<IInterface> make_end() = 0;
And implement:
public:
Iterator begin() { return Iterator(make_begin()); }
Iteraotr end() { return Iterator(make_end()); }
Note:
You can do away with the std::unique_ptr if you can avoid the ownership issue. If you can restrict the IInterface to be behavioral only (by extracting the state into Iterator), then you can have the Strategy pattern kick-in, and use a pointer a statically allocated object. This way, you avoid dynamic allocation of memory.
Of course, it means your iterators won't be so rich, as it requires IInterface implementations to be stateless, and implementing "filtering" iterators, for example, would become impossible.
Have you thought about using CRTP. I find it a good candidate here. Here is a brief demo. It just explains your ++retval problem (if I understood it correctly). You have to change your IInterface definition from pure virtual to CRTP type interface.
template<class Derived>
struct IInterface
{
Derived& operator ++ ()
{
return ++ *(static_cast<Derived*>(this));
}
};
struct Something : public IInterface<Something>
{
int x;
Something& operator ++ ()
{
++x;
return *this;
}
};
There are some limitations of CRTP, that the template will always follow your IInterface. Which means that if you are passing a Something object to a function like this:
foo(new Something);
Then, foo() should be defined as:
template<typename T>
void foo(IInterface<T> *p)
{
//...
++(*p);
}
However for your problem, it can be a good fit.
Like you said, the problem is that instances of Something are tied to the object it holds. So let's try to untie them.
The key point to remember is that in OOP, public non-const data members are generally frowned upon. In your current implementation, every Something instance is tied to having a data member T x which is publicly accessible. Instead of this, is considered better to make an abstraction of this, i.e. provide accessor methods instead:
class Something : IInterface
{
private:
T x;
public:
T GetX()
{
return x;
}
};
Now the user has know idea what type of thing x is, much less that x exists.
This is a good first step, however, since you wish be able to have x refer to different objects at different times, we're pretty much going to have to make x be a pointer. And as a concession to conventional code, we'll also make GetX() return a const reference, rather than a regular value:
class Something: IInterface
{
private:
T *x;
public:
T const& GetX()
{
return *x;
}
};
It's now trivial to implement the methods in IInterface:
class Something: IInterface
{
private:
T *x;
public:
T const& GetX()
{
return *x;
}
T& operator*()
{
return *x;
}
T* operator->()
{
return x;
}
Something& operator++()
{
++x;
return *this;
}
};
The ++ operator is trivial now - it really just applies the ++ to x.
The user now has no idea that a pointer was used. All they know is that their code works right. That's the most important point in OOP's principle of data abstraction.
Edit
As far as implementing the begin and end methods of Container, that shouldn't be too difficult either, but it will require some changes to Container.
First off, let's add a private constructor to Something which takes a pointer to the starting object. We'll also make MyContainer a friend of Something:
class Something: IInterface
{
friend class MyContainer; // Can't test the code right now - may need to be MyContainer<T> or ::MyContainer<T> or something.
private:
T *x;
Something( T * first )
: x(first)
{
}
public:
T const& GetX()
{
return *x;
}
T& operator*()
{
return *x;
}
T* operator->()
{
return x;
}
Something& operator++()
{
++x;
return *this;
}
};
By making the constructor private, and setting the friend dependancy, we ensure that only MyContainer can make new Something iterators (this protects us iterating over random memory if something erroneous were given by a user).
Next off, we'll change MyContainer a little, so that rather than having an array of Something, we'll just have an array of T:
class MyContainer
{
...
private:
T *data;
};
Before we get to implementing begin and end, let's make that change to Container I talked about:
template<typename T, typename IteratorType>
class Container {
public:
...
// These prototype are the key. Notice the return type is IteratorType (value, not reference)
virtual IteratorType begin() = 0;
virtual IteratorType end() = 0;
};
So rather than relying on covariance (which would be really difficult in this case), we use a little template magic to do what we want.
Of course, since Container now accepts another type parameter, we need a corresponding change to MyContainer; namely we need to provide Something as the type parameter to Container:
template<class T>
class MyContainer : Container<T, Something>
...
And the begin/end methods are now easy:
template<class T>
MyContainer<T>::begin()
{
return Something(data);
}
template<class T>
MyContainer<T>::end()
{
// this part depends on your implementation of MyContainer.
// I'll just assume your have a length field in MyContainer.
return Something(data + length);
}
So this is what I've got for my midnight thinking. Like I mentioned above, I cannot currently test this code, so you might have to tweak it a bit. Hopefully this does what you want.
If the usage is supposed to be similar to stdlib, then the iterator needs to be a value object, because it normally gets copied by value a lot. (Also, otherwise what would the begin and end method return a reference to?)
template <class T>
class Iterator
{
shared_ptr<IIterator> it;
public:
Iterator(shared_ptr<IIterator>);
T& operator*() { it->deref(); }
T* operator->() { return &it->deref(); }
Iterator& operator++() { it->inc(); return *this; }
etc.
};

How to implement function with vector of derived classes as parameter

(Related to a previous unanswered question I asked). I want to implement a function which can be called only with vectors of related classes as parameter.
For eq
if we have
class A;
class B: public A;
class C: public A;
class D
then it should be possible to call function with vector<A*>,vector<B*> or
vector <C*> but not vector <D*>
Any suggestions
I guess you already tried to create a method like
void doSomething(std::vector<A*>& things)
{
}
and tried do pass
std::vector<B*> bList = ...;
doSomething(bList);
right?
Why does the compiler complain? Because it would not make sense. Consider that doSomething() tries to do
things.push_back(new C());
This cannot work as "things" is actually a std::vector<B*>. However, if it were std::vector<A*>, push_back would work.
So what can we learn from this? What you're trying only makes sense if you only read from the vector, however, vector is not a read-only container.
A simple wrapper shows a possible solution (the wrapper can be adjusted to your needs, of course). However, I have to point out that the use of virtual methods might lead to performance penalties.
class A {};
class B : public A {};
template <class Base>
class AbstractVectorWrapper
{
public:
virtual size_t size() const = 0;
virtual Base* getElementAt(int index) const = 0;
};
template <class Base, class Derived>
class VectorWrapper : public AbstractVectorWrapper<Base>
{
private:
std::vector<Derived*> m_vector;
public:
explicit VectorWrapper(std::vector<Derived*> const& vector)
: m_vector(vector)
{
}
virtual size_t size() const
{
return m_vector.size();
}
virtual Base* getElementAt(int index) const
{
return m_vector[index];
}
};
void doSomething(AbstractVectorWrapper<A> const& wrapper)
{
for (size_t i=0;i<wrapper.size();i++)
{
A* a = wrapper.getElementAt(i);
}
}
int _tmain(int argc, _TCHAR* argv[])
{
std::vector<A*> as;
std::vector<B*> bs;
doSomething(VectorWrapper<A,B>(bs));
doSomething(VectorWrapper<A,A>(as));
return 0;
}
Is duck-typing good enough for you? Consider this code
template <class T>
void my_function (std::vector <T*> const &values) {
// Use features of A* here
}
This will fail to compile if you use features that pointers to T do not support. By using features of A I think it should be guaranteed that pointers to B and C will also work as expected. However, it would be possible to call this function with vectors of D *, provided D's interface complies with what my_function tries to do.