Today I learned about the C++ "memberspace" idiom, which roughly abuses a property of C++ that makes T::bar as well as T.bar work, when T is both a type and an object in some scope.
struct A {
struct Controls {
/* put some typedefs/data/functions here */
} Controls;
};
// Can be used as a type and value
A a;
A::Controls::iterator it = a.Controls.begin();
Have you ever used this idiom in practice? Have you found it useful? What's some good or the best application of the idiom?
No, I have never used that technique (and I don't think it deserves to be called an "idiom"):
Since I haven't used it, I haven't found it useful.
A good application of that technique could be to confuse other programmers.
Another application could be to write a techno-babble article about how wonderful it is for some imagined never-in-practice encountered problem, perhaps obfuscated with lots of template metaprogramming?
Dunno, best application would probably be to write an article about all those silly-rules, like you can also have a struct and a function of the same name in the same scope, as I recall, and point out how anything that those can accomplish, can be accomplished much better by staying away from the darker corners of the language. :-) Articles don't pay much in moneys but they pay in respect and are fun to write. Please write it (TIA).
Cheers & hth.,
As #Steve already said in a comment, the fact that the nested type and the instance of this type have the same name is not a central aspect of this technique. To increase encapsulation, we could even use a member function to access the instance (even though it would less look like a namespace qualification). For example, the example you gave could be rewritten as follow without any drawback (well, maybe there are, but I can't find any at the moment):
struct A
{
struct Controls
{
//typedefs/data/functions
};
const Controls & getControls() { return controls_; }
private:
Controls controls_;
};
A a;
A::Controls::iterator = a.getControls().begin();
Here is how I see memberspaces. The goal of memberspaces is to divide the naming space of a class in order to group together related typedefs and methods. The Controls class above could be defined outside of A, but it is so tightly connected to A (each A is associated with a Controls, and vice-versa, a Controls is nothing more than a view on the object A in which it is contained) that it feels "natural" to make it a member of A, and possibly also make it friend with A (if there is a need to access A's internals).
So basically memberspaces let us define one or several views on a single object, without polluting the enclosing class namespace. As noted in the article, this can be quite interesting when you want to provide several ways to iterate over an object of your class.
For example, let's assume that I am writing a class for representing C++ classes; let's call it Class. A Class has a name, and the list of all its base classes. For convenience reasons, I would like a Class to also store the list of all the classes that inherit from it (its derived classes). So I would have a code like that:
class Class
{
string name_;
list< shared_ptr< Class > > baseClasses_;
list< shared_ptr< Class > > derivedClasses_;
};
Now, I need some member functions to add/remove base classes/derived classes:
class Class
{
public:
void addBaseClass( shared_ptr< Class > base );
void removeBaseClass( shared_ptr< Class > base );
void addDerivedClass( shared_ptr< Class > derived );
void removeDerivedClass( shared_ptr< Class > derived );
private:
//... same as before
};
And sometimes, I might need to add a way to iterate over base classes and derived classes:
class Class
{
public:
typedef list< shared_ptr< Class > >::const_iterator const_iterator;
const_iterator baseClassesBegin() const;
const_iterator baseClassesEnd() const;
const_iterator derivedClassesBegin() const;
const_iterator derivedClassesEnd() const;
//...same as before
};
The amount of names we are dealing with is still manageable, but what if we want to add reverse iteration? What if we change the underlying type for storing derived classes? That would add another bunch of typedefs. Moreover, you have probably noticed that the way we provide access to begin and end iterators does not follow the standard naming, which means we can't use generic algorithms relying on it (such as Boost.Range) without additional effort.
In fact, it is obvious when looking at the member functions name that we used a prefix/suffix to logically group them, things that we try to avoid now that we have namespaces. But since we can't have namespaces in classes, we need to use a trick.
Now, using memberspaces, we encapsulate all base-related and derived-related information in their own class, which not only let us group together related data/operations, but can also reduce code duplication: since the code for manipulating base classes and derived classes is the same, we can even use a single nested class:
class Class
{
struct ClassesContainer
{
typedef list< shared_ptr< Class > > const_iterator;
ClassesContainer( list< shared_ptr< Class > > & classes )
: classes_( classes )
{}
const_iterator begin() const { return classes_.begin(); }
const_iterator end() const { return classes_.end(); }
void add( shared_ptr< Class > someClass ) { classes_.push_back( someClass ); }
void remove( shared_ptr< Class > someClass ) { classes.erase( someClass ); }
private:
list< shared_ptr< Class > > & classes_;
};
public:
typedef ClassesContainer BaseClasses;
typedef ClassesContainer DerivedClasses;
// public member for simplicity; could be accessible through a function
BaseClasses baseClasses; // constructed with baseClasses_
DerivedClasses derivedClasses; // constructed with derivedClasses_
// ... same as before
};
Now I can do:
Class c;
Class::DerivedClasses::const_iterator = c.derivedClasses.begin();
boost::algorithm::find( c.derivedClasses, & c );
...
In this example, the nested class is not so coupled to Class, so it could be defined outside, but you could find examples with a stronger bound.
Well, after this long post, I notice that I did not really answer your question :). So no, I never actually used memberspaces in my code, but I think it has its applications.
I have considered it once or twice, notably when I was writing a facade class for a library: the facade was meant to make the library easier to use by having a single entry point, but as a consequence it had several member functions, which were all related, but with different degrees of "relatedness". Moreover, it represented a collection of objects, so it contained iteration-related typedefs and member functions in addition to "features-oriented" member functions. I considered using memberspaces to divide the class in logical "subspaces" in order to have a cleaner interface. Don't know why I haven't done it.
No, I've never used that.
A good use for it? Maybe you can use it to show your colleagues that you are better they are... just like some pleople use templates where they shoudn't, for a complex solution to a simple problem (note that templates, unlike memberspace idiom, sometimes are useful).
Any syntax flexibility is always welcomed regardless of whether is it is potentially confusing or not. In fact the trick is used in boost.array, this is a minimal implementation:
#include<cassert>
template<unsigned N>
struct fixed_array{ /* bla bla */
static unsigned size(){
return N;
}
};
int main(){
fixed_array<3> arr;
assert(arr.size() == 3); //like a stl container
assert(fixed_array<3>::size() == 3); //more proper, but less generic wrt stl containers
return 0;
}
so if the user wants to see a static member function/static member variable/nested class as a property of the instance and not the class then he/she can. Useful to write generic code for example, and it is not confusing at all in this example.
Related
Background:
I've inherited a large system that makes use of templates to store meta data about classes, that may have colored some of the assumptions inherent in this question.
I'm making use of a template registration system that is partially based on an answer found here: Is there a way to instantiate objects from a string holding their class name? . Macros are a no go in my system, as is the use of boost (or really any third party API).
Question:
Can I have templates that behave differently based on whether the input type is abstract versus concrete?
I'm looking for something like this (Code used here directly copied from the accepted answer in the linked question):
struct BaseFactory {
typedef std::map<std::string, Base*(*)()> map_type;
static Base * createInstance(std::string const& s) {
map_type::iterator it = getMap()->find(s);
if(it == getMap()->end())
return 0;
return it->second();
}
protected:
static map_type * getMap() {
// never delete'ed. (exist until program termination)
// because we can't guarantee correct destruction order
if(!map) { map = new map_type; }
return map;
}
private:
static map_type * map;
};
template<typename T>
struct DerivedRegister : BaseFactory {
DerivedRegister(std::string const& s) {
getMap()->insert(std::make_pair(s, &createT<T>));
}
};
// in derivedb.hpp
class DerivedB {
...;
private:
static DerivedRegister<DerivedB> reg;
};
// in derivedb.cpp:
DerivedRegister<DerivedB> DerivedB::reg("DerivedB");
Except that I would like DerivedRegister to behave differently based on whether T is abstract versus concrete. In the case where T is abstract, I would expect DerivedRegister to not register the type with the map.
As I mentioned in the background, I've already inherited an existing system which already exists on the class hierarchy (abstract or concrete). It was trivial to modify this existing system to add the map registration; however, the abstract classes are causing problems since calling new on them isn't valid.
Adding additional layers of inheritance and templating between BaseFactory and DerivedRegister wouldn't be a problem; however, DerivedRegister already exists on every class and I can't change that.
I recognize that I could just add a unique registration system independent of the existing template classes and only add it to the concrete classes. I'm specifically asking if there is a solution where I can avoid that in C++11 without using third party libraries (lots of restrictions I know...).
Use std::is_abstract:
If T is an abstract class (that is, a non-union class that declares or inherits at least one pure virtual function), provides the member constant value equal to true. For any other type, value is false.
I have a class that adapts std::vector to model a container of domain-specific objects. I want to expose most of the std::vector API to the user, so that they may use familiar methods (size, clear, at, etc...) and standard algorithms on the container. This seems to be a reoccurring pattern for me in my designs:
class MyContainer : public std::vector<MyObject>
{
public:
// Redeclare all container traits: value_type, iterator, etc...
// Domain-specific constructors
// (more useful to the user than std::vector ones...)
// Add a few domain-specific helper methods...
// Perhaps modify or hide a few methods (domain-related)
};
I'm aware of the practice of preferring composition to inheritance when reusing a class for implementation -- but there's gotta be a limit! If I were to delegate everything to std::vector, there would be (by my count) 32 forwarding functions!
So my questions are... Is it really so bad to inherit implementation in such cases? What are the risks? Is there a safer way I can implement this without so much typing? Am I a heretic for using implementation inheritance? :)
Edit:
What about making it clear that the user should not use MyContainer via a std::vector<> pointer:
// non_api_header_file.h
namespace detail
{
typedef std::vector<MyObject> MyObjectBase;
}
// api_header_file.h
class MyContainer : public detail::MyObjectBase
{
// ...
};
The boost libraries seem to do this stuff all the time.
Edit 2:
One of the suggestions was to use free functions. I'll show it here as pseudo-code:
typedef std::vector<MyObject> MyCollection;
void specialCollectionInitializer(MyCollection& c, arguments...);
result specialCollectionFunction(const MyCollection& c);
etc...
A more OO way of doing it:
typedef std::vector<MyObject> MyCollection;
class MyCollectionWrapper
{
public:
// Constructor
MyCollectionWrapper(arguments...) {construct coll_}
// Access collection directly
MyCollection& collection() {return coll_;}
const MyCollection& collection() const {return coll_;}
// Special domain-related methods
result mySpecialMethod(arguments...);
private:
MyCollection coll_;
// Other domain-specific member variables used
// in conjunction with the collection.
}
The risk is deallocating through a pointer to the base class (delete, delete[], and potentially other deallocation methods). Since these classes (deque, map, string, etc.) don't have virtual dtors, it's impossible to clean them up properly with only a pointer to those classes:
struct BadExample : vector<int> {};
int main() {
vector<int>* p = new BadExample();
delete p; // this is Undefined Behavior
return 0;
}
That said, if you're willing to make sure you never accidentally do this, there's little major drawback to inheriting them—but in some cases that's a big if. Other drawbacks include clashing with implementation specifics and extensions (some of which may not use reserved identifiers) and dealing with bloated interfaces (string in particular). However, inheritance is intended in some cases, as container adapters like stack have a protected member c (the underlying container they adapt), and it's almost only accessible from a derived class instance.
Instead of either inheritance or composition, consider writing free functions which take either an iterator pair or a container reference, and operate on that. Practically all of <algorithm> is an example of this; and make_heap, pop_heap, and push_heap, in particular, are an example of using free functions instead of a domain-specific container.
So, use the container classes for your data types, and still call the free functions for your domain-specific logic. But you can still achieve some modularity using a typedef, which allows you to both simplify declaring them and provides a single point if part of them needs to change:
typedef std::deque<int, MyAllocator> Example;
// ...
Example c (42);
example_algorithm(c);
example_algorithm2(c.begin() + 5, c.end() - 5);
Example::iterator i; // nested types are especially easier
Notice the value_type and allocator can change without affecting later code using the typedef, and even the container can change from a deque to a vector.
You can combine private inheritance and the 'using' keyword to work around most of the problems mentioned above: Private inheritance is 'is-implemented-in-terms-of' and as it is private you cannot hold a pointer to the base class
#include <string>
#include <iostream>
class MyString : private std::string
{
public:
MyString(std::string s) : std::string(s) {}
using std::string::size;
std::string fooMe(){ return std::string("Foo: ") + *this; }
};
int main()
{
MyString s("Hi");
std::cout << "MyString.size(): " << s.size() << std::endl;
std::cout << "MyString.fooMe(): " << s.fooMe() << std::endl;
}
As everyone has already stated, STL containers do not have virtual destructors so inheriting from them is unsafe at best. I've always considered generic programming with templates as a different style of OO - one without inheritance. The algorithms define the interface that they require. It is as close to Duck Typing as you can get in a static language.
Anyway, I do have something to add to the discussion. The way that I have created my own template specializations previously is to define classes like the following to use as base classes.
template <typename Container>
class readonly_container_facade {
public:
typedef typename Container::size_type size_type;
typedef typename Container::const_iterator const_iterator;
virtual ~readonly_container_facade() {}
inline bool empty() const { return container.empty(); }
inline const_iterator begin() const { return container.begin(); }
inline const_iterator end() const { return container.end(); }
inline size_type size() const { return container.size(); }
protected: // hide to force inherited usage only
readonly_container_facade() {}
protected: // hide assignment by default
readonly_container_facade(readonly_container_facade const& other):
: container(other.container) {}
readonly_container_facade& operator=(readonly_container_facade& other) {
container = other.container;
return *this;
}
protected:
Container container;
};
template <typename Container>
class writable_container_facade: public readable_container_facade<Container> {
public:
typedef typename Container::iterator iterator;
writable_container_facade(writable_container_facade& other)
readonly_container_facade(other) {}
virtual ~writable_container_facade() {}
inline iterator begin() { return container.begin(); }
inline iterator end() { return container.end(); }
writable_container_facade& operator=(writable_container_facade& other) {
readable_container_facade<Container>::operator=(other);
return *this;
}
};
These classes expose the same interface as an STL container. I did like the effect of separating the modifying and non-modifying operations into distinct base classes. This has a really nice effect on const-correctness. The one downside is that you have to extend the interface if you want to use these with associative containers. I haven't run into the need though.
In this case, inheriting is a bad idea: the STL containers do not have virtual destructors so you might run into memory leaks (plus, it's an indication that STL containers are not meant to be inherited in the first place).
If you just need to add some functionality, you can declare it in global methods, or a lightweight class with a container member pointer/reference. This off course doesn't allow you to hide methods: if that is really what you are after, then there's no other option then redeclaring the entire implementation.
Virtual dtors aside, the decision to inherit versus contain should be a design decision based the class you are creating. You should never inherit container functionality just because its easier than containing a container and adding a few add and remove functions that seem like simplistic wrappers unless you can definitively say that the class you are creating is a kind-of the container. For instance, a classroom class will often contain student objects, but a classroom isn't a kind of list of students for most purposes, so you shouldn't be inheriting from list.
It is easier to do:
typedef std::vector<MyObject> MyContainer;
The forwarding methods will be inlined away, anyhow. You will not get better performance this way. In fact, you will likely get worse performance.
Always consider composition over inheritance.
Consider the case:
class __declspec(dllexport) Foo :
public std::multimap<std::string, std::string> {};
Then symbols of std::multimap will be exported into your dll, which may cause compilation error "std::multimap already defined".
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Pros and cons of using nested C++ classes and enumerations?
Consider the following declaration.
class A {
public:
class B{
};
};
Nothing special.
But what are the benefits of this?
What reasons may there be for putting one class inside of another?
There is no inheritance benefit between both classes.
If B is put inside of A for its private names sharing, then A is for B just a namespace, and there is reason to make B private, too.
What do you think about this?
Conceptually, it lets the programmer(s) know that class B relates specifically to class A. When you use class B outside of class A, you must use the type as A::B, which reminds you, every time, that B is related to A. This doesn't add any functionality, but shows a relationship.
Similarly, you don't have to use inheritance/composition, or classes at all. You can more or less simulate classes in C just by using structs and functions. It's just a way to keep the code cleaner and more straightforward and let the programmer relate the code to the design more easily. Classes accomplish this much more than public subclasses do, but that's just an example.
If it's a private/protected subclass (which I see it isn't in your example), then that obviously limits that class to the implementation of that class and that class's children, which might be desired (again design-wise) if the only use case of that class is in the implementation of that class (and possibly its children).
Benefit 1: The namespace aspect
Indeed, A provides a namespace for B, and this can help us structure our code much better. Consider a concrete example with vector for A, and iterator for B. Arguably,
class vector {
public:
class iterator { /*...*/ };
iterator begin() { /*...*/ }
};
is easier to type, to read, and to understand than
class vector_iterator {
/*...*/
};
class vector {
public:
vector_iterator begin() { /*...*/ }
};
Observe, in particular:
When the two classes (vector and iterator) depend on each other, i.e. use each other's members, the second version above would require one of the two to be forward-declared, and in some cases mutual type-dependencies might lead to unresolvable situations. (Using nested classes, it is much easier to avoid such problems, because within most parts of the nested class definition, the outer class is considered completely-defined. This is due to §9.2/2.)
You may very well have many other data types that maintain their own iterator, e.g. linked_list. Using the second version above, you'd need to define linked_list_iterator as a separate class. Class names would get ever longer and complicated the more of these 'dependent' types and alternative types you added.
Benefit 2: Templates
Continuing the example above, consider now a function template that takes a container (such as vector and linked_list defined above) as arguments and iterates over them:
template <typename Container>
void iterate(const Container &container) {
/*...*/
}
Inside this function, you'd obviously very much like to use the iterator type of Container. If that is a nested type, it's easy:
typename Container::iterator
But if it isn't, you would have to take the iterator type as a separate template parameter:
template <typename Container, typename Iterator>
void iterate(const Container &container) {
/*...*/
Iterator it = container.begin();
/*...*/
}
And if that iterator type does not appear among the function arguments, the compiler could not even guess the type. You'd have to explicitly add it in angle brackets each time you call the iterate function.
Final notes: None of this has much to do with whether the nested class is declared as public or private. My examples above suggest a situation in which a public nested type is clearly preferrable, because I suppose the iterator type should be able to be used outside the container class.
What reasons may be for putting one class inside of another one?
If you need to restrict the scope of B to only available for A, then internal class definition helps. Because it restricts the class scope to local.This is call scope localization.These are in more generic term called inner class declaration. Check this link.
This stackoverflow question helps you understand more.
Can someone please point me towards some nice resources for understanding and using nested classes? I have some material like Programming Principles and things like this IBM Knowledge Center - Nested Classes
But I'm still having trouble understanding their purpose. Could someone please help me?
Nested classes are cool for hiding implementation details.
List:
class List
{
public:
List(): head(nullptr), tail(nullptr) {}
private:
class Node
{
public:
int data;
Node* next;
Node* prev;
};
private:
Node* head;
Node* tail;
};
Here I don't want to expose Node as other people may decide to use the class and that would hinder me from updating my class as anything exposed is part of the public API and must be maintained forever. By making the class private, I not only hide the implementation I am also saying this is mine and I may change it at any time so you can not use it.
Look at std::list or std::map they all contain hidden classes (or do they?). The point is they may or may not, but because the implementation is private and hidden the builders of the STL were able to update the code without affecting how you used the code, or leaving a lot of old baggage laying around the STL because they need to maintain backwards compatibility with some fool who decided they wanted to use the Node class that was hidden inside list.
Nested classes are just like regular classes, but:
they have additional access restriction (as all definitions inside a class definition do),
they don't pollute the given namespace, e.g. global namespace. If you feel that class B is so deeply connected to class A, but the objects of A and B are not necessarily related, then you might want the class B to be only accessible via scoping the A class (it would be referred to as A::Class).
Some examples:
Publicly nesting class to put it in a scope of relevant class
Assume you want to have a class SomeSpecificCollection which would aggregate objects of class Element. You can then either:
declare two classes: SomeSpecificCollection and Element - bad, because the name "Element" is general enough in order to cause a possible name clash
introduce a namespace someSpecificCollection and declare classes someSpecificCollection::Collection and someSpecificCollection::Element. No risk of name clash, but can it get any more verbose?
declare two global classes SomeSpecificCollection and SomeSpecificCollectionElement - which has minor drawbacks, but is probably OK.
declare global class SomeSpecificCollection and class Element as its nested class. Then:
you don't risk any name clashes as Element is not in the global namespace,
in implementation of SomeSpecificCollection you refer to just Element, and everywhere else as SomeSpecificCollection::Element - which looks +- the same as 3., but more clear
it gets plain simple that it's "an element of a specific collection", not "a specific element of a collection"
it is visible that SomeSpecificCollection is also a class.
In my opinion, the last variant is definitely the most intuitive and hence best design.
Let me stress - It's not a big difference from making two global classes with more verbose names. It just a tiny little detail, but imho it makes the code more clear.
Introducing another scope inside a class scope
This is especially useful for introducing typedefs or enums. I'll just post a code example here:
class Product {
public:
enum ProductType {
FANCY, AWESOME, USEFUL
};
enum ProductBoxType {
BOX, BAG, CRATE
};
Product(ProductType t, ProductBoxType b, String name);
// the rest of the class: fields, methods
};
One then will call:
Product p(Product::FANCY, Product::BOX);
But when looking at code completion proposals for Product::, one will often get all the possible enum values (BOX, FANCY, CRATE) listed and it's easy to make a mistake here (C++0x's strongly typed enums kind of solve that, but never mind).
But if you introduce additional scope for those enums using nested classes, things could look like:
class Product {
public:
struct ProductType {
enum Enum { FANCY, AWESOME, USEFUL };
};
struct ProductBoxType {
enum Enum { BOX, BAG, CRATE };
};
Product(ProductType::Enum t, ProductBoxType::Enum b, String name);
// the rest of the class: fields, methods
};
Then the call looks like:
Product p(Product::ProductType::FANCY, Product::ProductBoxType::BOX);
Then by typing Product::ProductType:: in an IDE, one will get only the enums from the desired scope suggested. This also reduces the risk of making a mistake.
Of course this may not be needed for small classes, but if one has a lot of enums, then it makes things easier for the client programmers.
In the same way, you could "organise" a big bunch of typedefs in a template, if you ever had the need to. It's a useful pattern sometimes.
The PIMPL idiom
The PIMPL (short for Pointer to IMPLementation) is an idiom useful to remove the implementation details of a class from the header. This reduces the need of recompiling classes depending on the class' header whenever the "implementation" part of the header changes.
It's usually implemented using a nested class:
X.h:
class X {
public:
X();
virtual ~X();
void publicInterface();
void publicInterface2();
private:
struct Impl;
std::unique_ptr<Impl> impl;
}
X.cpp:
#include "X.h"
#include <windows.h>
struct X::Impl {
HWND hWnd; // this field is a part of the class, but no need to include windows.h in header
// all private fields, methods go here
void privateMethod(HWND wnd);
void privateMethod();
};
X::X() : impl(new Impl()) {
// ...
}
// and the rest of definitions go here
This is particularly useful if the full class definition needs the definition of types from some external library which has a heavy or just ugly header file (take WinAPI). If you use PIMPL, then you can enclose any WinAPI-specific functionality only in .cpp and never include it in .h.
I don't use nested classes much, but I do use them now and then. Especially when I define some kind of data type, and I then want to define a STL functor designed for that data type.
For example, consider a generic Field class that has an ID number, a type code and a field name. If I want to search a vector of these Fields by either ID number or name, I might construct a functor to do so:
class Field
{
public:
unsigned id_;
string name_;
unsigned type_;
class match : public std::unary_function<bool, Field>
{
public:
match(const string& name) : name_(name), has_name_(true) {};
match(unsigned id) : id_(id), has_id_(true) {};
bool operator()(const Field& rhs) const
{
bool ret = true;
if( ret && has_id_ ) ret = id_ == rhs.id_;
if( ret && has_name_ ) ret = name_ == rhs.name_;
return ret;
};
private:
unsigned id_;
bool has_id_;
string name_;
bool has_name_;
};
};
Then code that needs to search for these Fields can use the match scoped within the Field class itself:
vector<Field>::const_iterator it = find_if(fields.begin(), fields.end(), Field::match("FieldName"));
One can implement a Builder pattern with nested class. Especially in C++, personally I find it semantically cleaner. For example:
class Product{
public:
class Builder;
}
class Product::Builder {
// Builder Implementation
}
Rather than:
class Product {}
class ProductBuilder {}
I think the main purpose of making a class to be nested instead of just a friend class is the ability to inherit nested class within derived one. Friendship is not inherited in C++.
You also can think about first class ass type of main function, where You initiate all needed classes to work togheter. Like for example class Game, initiate all other classes like windows, heroes, enemy's, levels and so on. This way You can get rid all that stuff from main function it self. Where You can create obiect of Game, and maybe do some extra external call not related to Gemente it self.
Consider the following example code:
class Foo
{
};
class Bar : public Foo
{
};
class FooCollection
{
protected:
vector<shared_ptr<Foo> > d_foos;
};
class BarCollection : public FooCollection
{
public:
vector<shared_ptr<Bar> > &getBars()
{
// return d_foos won't do here...
}
};
I have a problem like this in my current project. The client code uses BarCollection, which stores pointers to Bars in d_foos which is declared in FooCollection. I'd now like to expose the collection of pointers to Bars to the client code. I could just give the client code access to the vector of pointers to Foos and cast these to pointers to Bars in the client code, but this feels wrong since the client doesn't have to know about Foo's existence.
I could also define a get() member that retrieves objects from d_foos and casts them, but this feels quite clumsy. Preferably, I'd like to just return d_foos as a vector<shared_ptr<Bar> > &, but I cannot seem to do this.
It could also be that my design is just plain wrong. It seemed to most natural solution though, as Bar is a specialization of Foo and BarCollection is a specialization of FooCollection and they share functionality.
Could you suggest nice solutions to implement getBars in BarCollection or better design alternatives?
Edit:
Turns out my design was bad indeed. BarCollection is not a FooCollection, despite of requiring all of FooCollection's functionality. My current solution based on the answers below -- which is a lot cleaner -- is now:
class Foo
{
};
class Bar : public Foo
{
};
template<class T>
class Collection
{
vector<shared_ptr<T> > d_items;
};
typedef Collection<Foo> FooCollection;
class BarCollection : public Collection<Bar>
{
// Additional stuff here.
};
Thanks for all the excellent suggestions and examples!
I would suggest exposing iterators from your container classes, instead of the member container. That way it won't matter what the container type is.
The problem is you are trying to mix-and-match two different, pretty-much independent kinds of polymorphism in a way that won't work. The compile-time, type-safe polymorphism of templates won't allow you to substitute a base type for a derived type. C++'s template system makes no association between
class<Foo>
and
class<Bar>
One suggestion might be to create a Foo derived adapter that would cast down to the correct class:
template <class derived, class base>
class DowncastContainerAdapter
{
private:
std::vector< boost::shared_ptr<base> >::iterator curr;
std::vector< boost::shared_ptr<base> >::const_iterator end;
public:
DowncastContainerAdapter(/*setup curr & end iterators*/)
{
// assert derived actually is derived from base
}
boost::shared_ptr<derived> GetNext()
{
// increment iterator
++curr;
return dynamic_cast<base>(*curr);
}
bool IsEnd()
{
return (curr == end);
}
};
Note this class will have the same problem as an iterator, operation on the vector may invalidate this class.
Another thought
You may not realize it, but it may be perfectly fine to just return a vector of Foo. The user of Bar already must have full knowledge of Foo, since by including Bar.h they must get Foo.h through Bar.h. The reason being that for Bar to inherit from Foo, it must have full knowledge of the class via Foo.h. I would suggest rather than using the solution above, if it's possible make Foo (or a super class of Foo) an interface class and pass around vectors of pointers to that interface class. This is a pretty commonly seen pattern and won't raise the eyebrows that this wonky solution I came up with might :). Then again you may have your reasons. Good luck either way.
template<class T>
class MyContainer {
vector<shared_ptr<T> > d_foos;
public:
vector<shared_ptr<T> > & getVector();
};
class FooCollection : public MyContainer<Foo> {
};
class BarCollection : public MyContainer<Bar> {
};
The question is, why would you do that? If you give the user a collection of pointers to Bar, you assume, that there are only Bars in it, so internally storing the pointers in a collection to Foo makes no sense. If you store different subtypes of Foo in your collection of pointer to Foo, you cannot return it as a collection of pointers to Bar, since not all objects in there are Bars.
In the first case, (you know that you have only bars) you should use a templated approach as suggested above.
Otherwise, you have to rethink, what you really want.
Can you not replace this with a Collection templatized on either Foo / Bar?, something like this
class Collection<T> {
protected:
vector<shared_ptr<T> > d_foos;
};
typedef Collection<Foo> FooCollection;
typedef Collection<Bar> BarCollection;
Do you have a special need to have BarCollection derived from FooCollection? Because generally a BarCollection is not a FooCollection, usually a lot of the things that can be done with a FooCollection should not be done with a BarCollection. For example:
BarCollection *bc = new BarCollection();
FooCollection *fc = bc; // They are derived from each other to be able to do this
fc->addFoo(Foo()); // Of course we can add a Foo to a FooCollection
Now we have added a Foo object to what is supposed to be a BarCollection. If the BarCollection tries to access this newly added element and expects it to be a Bar, all kinds of ugly things will happen.
So usually you want to avoid this and don't have your collection classes derived from each other. See also questions about casting containers of derived types for more answers on this topic...
First of all, let's talk about shared_ptr. Do you know about: boost::detail::dynamic_cast_tag ?
shared_ptr<Foo> fooPtr(new Bar());
shared_ptr<Bar> barPtr(fooPtr, boost::detail::dynamic_cast_tag());
This is a very handy way. Under the cover it just performs a dynamic_cast, nothing fancy there but an easier notation. The contract is the same that the classic one: if the object pointed to does not actually is a Bar (or derived from it), then you get a null pointer.
Back to your question: BAD CODE.
BarCollection is NOT a FooCollection, as mentioned you are therefore in trouble because you could introduce other elements in the vector of pointers that Bar ones.
I won't extend on that though, because this is beyond the question at hand, and I think that we (as those trying to answer) should restrain ourselves from that.
You cannot pass a reference, but you can pass a View.
Basically, a View is a new object that act as a Proxy to the old one. It's relatively easy using Boost.Iterators from example.
class VectorView
{
typedef std::vector< std::shared_ptr<Foo> > base_type;
public:
typedef Bar value_type;
// all the cluttering
class iterator: boost::iterator::iterator_adaptor<
iterator,
typename base_type::iterator,
std::shared_ptr<Bar>
>
{
typename iterator_adaptor::reference dereference() const
{
// If you have a heart weakness, you'd better stop here...
return reinterpret_cast< std::shared_ptr<Bar> >(this->base_reference());
}
};
// idem for const_iterator
// On to the method forwarding
iterator begin() { return iterator(m_reference.begin()); }
private:
base_type& m_reference;
}; // class VectorView
The real problem here is of course the reference bit. Getting a NEW shared_ptr object is easy, and allow to perform a dynamic_cast as required. Getting a reference to the ORIGINAL shared_ptr but interpreted as the required type... is really not what I like to see in code.
Note:
There might be a way to do better than that using Boost.Fusion transform_view class, but I could not figure it out.
In particular, using transform_view I can get shared_ptr<Bar> but I can't get a shared_ptr<Bar>& when I dereference my iterator, which is annoying given that the only use of returning a reference to the underlying vector (and not a const_reference) is to actually modify the structure of the vector and the objects it contains.
Note 2:
Please consider refactoring. There have been excellent suggestions there.