I'm writing an intrusive linked list
class ListAlgorithm {
ListNode& next(ListNode& n) {
//returns an object of type ListNode linked to n.
}
};
Users usually want to add some features (such as some additional data) on ListNode like this:
class UserNode : public ListNode {
void operationOnUserData();
int userData;
};
Then users have to downcast ListNode returned by 'next' into UserNode. It is inconvenient. Thus, I tried to make ListAlgorithm a template class :
//U extends ListNode
template<class U>
class ListAlgorihtm {
U& next(U& u);
};
But then I have to upcast u into ListNode inside the method 'next' because class U could accidentally hide some members of ListNode that ListAlgorithm uses. This is error-prone because I could forget the upcast and compiler will not warn about that. I have to downcast ListNode into U again for the return value but it is safe because 'next' takes an instance u of U and the return value is something from u.
Another trial is
//U extends ListNode
template<class U>
class ListAlgorhtm {
U& next(ListNode& n);
};
In this case, the upcast problem is not there, but I have to downcast ListNode into U for the return value and it is not safe because it is not sure that n is an instance of U. It could be an instance of another type extending ListNode.
What is the best solution in this case? I think this is a very elementary design problem and I'd like to know what kind of material I have to study for basic OO design like this.
Your actual problem here is that you allow users to subclass ListNode and mess with its semantics by adding arbitrary data and operations to ListNode objects through subclassing. This therefore makes it necessary for the user to interpret the ListNode& return values of actual ListNode methods as something that those return values are not, semantically speaking.
This problem of a semantic nature is reflected in how tedious your code suddenly becomes, with casts and templating of an unrelated class (ListAlgorithm) which is due to your problem "propagating" and infecting other parts of your code.
Here's a solution: a ListNode object should not be allowed to also be a UserNode object. However, it should be allowed to have, to carry with it a UserData object that can be retrieved and manipulated.
In other words, your list becomes a simple container template, like std::list, and the users can specify the operations and data members that they need as part of the definition of the class they use as the template argument.
class IListNode
{
public:
// whatever public methods you want here
protected:
// pure virtual methods maybe?
};
class ListNode : public IListNode
{
// List node class, no data
};
template<class UserDataType>
class ListNodeWithData : public IListNode
{
private:
UserDataType data;
public:
ListNodeWithData <UserDataType>(UserDataType &data) :
data(data)
{ }
const UserDataType& getData() {
return data;
}
};
class ListAlgorithm
{
public:
template<class UserDataType>
ListNodeWithData<UserDataType>& next(const ListNodeWithData<UserDataType>& node) {
// Do stuff
}
ListNode& next(const ListNode& node) {
// Do stuff, which may be very similar to the stuff done above
// in which case you may want to prefer to just define the
// method below, and remove this one and the one above:
}
// You should define either this method or the two above, but having
// them all is possible too, if you find a use for it
IListNode& next(const IListNode& node) {
// Do generic stuff
}
};
As far as the size of the resulting classes is concerned, I just know it will increase if you use virtual methods in IListNode.
As far as the issue you raise goes, any time you want to operate on members of a class and avoid hiding by a derived class, just make sure your operations are on the base, so
template<class U>
class ListAlgorihtm {
public:
U& next(U& u) {
return static_cast<U&>(return nextNode(u));
}
private:
ListNode& nextNode(ListNode& n);
};
That said, you have a lot of options for this problem set. The Boost library has an "intrusive" library that embeds node information either as base_hook (as a base of the user data) or member_hook (as a member of the class, which avoids some of the problems you describe). Check it out at http://www.boost.org/doc/libs/1_57_0/doc/html/intrusive.html.
Related
I have a generic reference-counted heap-allocated wrapper class. So my class is basically just a pointer:
template <typename T>
class Refcounted {
struct model {
std::atomic<std::size_t> count{1};
T value;
};
model* m_self;
public:
...
Refcounted(const Refcounted& other) : m_self(other.m_self) {
assert(m_self);
++m_self->count;
}
...
T& operator*() { return m_model->value; }
};
Now, I'd like to be able to get a T& even in a context where T is forward-declared. As I understand it, I can't, because if T is just forward-declared, it can't know the layout of model (in particular, it can't know the offset of value because it can't know T's alignment).
I believe that if I swapped the order of model, it would be well-defined behavior to reinterpret_cast, correct?:
template <typename T>
class Refcounted {
struct model {
T value;
std::atomic<std::size_t> count{1};
};
model* m_self;
public:
Refcounted(T&& x) : m_self(new model(std::move(x))) {
static_assert(offsetof(model, value) == 0, "Using this assumption below to reinterpret_cast");
}
...
Refcounted(const Refcounted& other) : m_self(other.m_self) {
assert(m_self);
++m_self->count;
}
...
T& operator*() { return *reinterpret_cast<T*>(m_model); }
};
Assuming that's correct, great... but now the copy-constructor requires T to be defined because it needs to find m_self->count. I had a thought for dealing with that, but I suspect it's UB: If I set up the model struct so that std::atomic<std::size_t> count is first and there's no padding between it and the T, then Refcounted keeps a void* pointer to the value field, as in m_valptr{&(new model(std::move(x)))->value}, then I could reinterpret_cast<T*>(m_valptr) to get at the value (which I think (?) is still well-defined-behavior). Is there any defined way to go from that pointer to a pointer to count? In principal, it's just decrementing the pointer by std::atomic<std::size_t>, but I suspect it breaks rules that I don't fully understand about what can and cannot be done with pointers.
I could add a second pointer to Refcounted or I could make model use a virtual interface, but that adds overhead. I feel like this should be possible but that there are spooky language rules getting in the way.
I've tried implementing a list container,
and decided to move some general functions
like sum() to base class, so that I can
reuse them later in other containers.
All the base support class needs are three
methods empty(), head() and tail.
I can't make those pure virtual because support
class will never be instantiated. But it still
has to use those methods to implement its own
methods like sum().
I tried something like this:
#include <iostream>
using namespace std;
template<typename T>
class StatsSupport {
public:
T sum(void) const {
if (empty()) {
return T(0);
} else {
return head() + tail()->sum;
}
}
// other methods
};
template<typename T>
class List : public StatsSupport<T> {
public:
// constructors etc.
bool empty(void) const {return head_ != NULL;}
const T& head(void) const {return *head_;}
const List<T>& tail(void) const {return *tail_;}
// other methods
private:
T* head_;
List<T> *tail_;
};
But trying to use sum() gets me compilation error
prog.cpp:8:13: error: there are no arguments to 'empty' that depend on a template parameter, so a declaration of 'empty' must be available [-fpermissive]
if (empty()) {
^
for each of empty(), head() and tail().
Any advice?
The problem is that StatsSupport cannot find the empty, head etc. functions because these neither exist in its nor in the global scope.
StatsSupport does not know about the functions that exist in the derived class.
Basically there are two ways to solve this:
Runtime polymorphism, where you add a virtual destructor to StatsSupport and add declarations for empty, head etc. which are pure virtual.
Compile time polymorphism via using CRTP as mentioned in the comments.
I will focus on the latter.
So basically StatsSupport needs to get a way to access functions of the derived class.
This can be done by adding the type of the derived class as template parameter, which is called CRTP:
template<class Derived, typename T>
class StatsSupport {
public:
T sum(void) const {
if (derived()->empty()) {
return T(0);
} else {
return derived()->head() + derived()->tail()->sum;
}
}
// other methods
private:
Derived *derived()
{
return static_cast<Derived*>(this);
}
const Derived *derived() const
{
return static_cast<const Derived*>(this);
}
};
template<typename T>
class List : public StatsSupport<List<T>, T> { // with some changes could be simplified to StatsSupport<List<T>> but this it ouf of scope of this question
I am using a function for derived instead of a member to keep the class const correct.
Of course another alternative would be a different design relying on algorithms. There you move sum and all the other functions of StatsSupport into global namesapce and would then access them like sum(my_container_instance).
A more STL like way would be to use iterators. Then you could use std::accumulate to do the summing.
That's a serious design issue: Your StatSupport defines some general functions, but relies on specifics of its child classes.
So when StatSupport gets compiled, it doesn't even know that there is some head() and tail(). That's why you get the error message
Now imagine that one day you want to define other containers that shall inherit from StatSupport, for example your own Vector or Map, or DataBase. These data structures will not have a head and a tail.
Basically there are two main orientations you may take:
define in your StatSupport some virtual functions for iterating through the data structure.
or better, use in your data structures some iterators (like they exist for standard containers) and define some template functions (sum, average, etc...) that use iterators to browse through your container.
In the latter case, you wouldn't need inheritance to benefit from generic functions.
I might miss the point of the question but will give my 5 cents to it anyway :)
The reasoning behind the solution I show below is, that often people new to OOP (in C++) think that they must use inheritance to get things done.
But especially in C++, this is but one way and often not the best way to achieve composition.
While in the majority of cases, the overhead cost of virtual functions does not really matter, the code below shows a way to yield container expansions without using inheritance and without using virtual functions. The weak point of the approach is that the "container function contract" is only implicitly visible.
template <class _X>
class ContainerTypeA < _X >
{
public:
typedef _X value_type;
typedef ContainerTypeA<_X> container_type;
const _X & Head() const
{
// return head of this containers content.
}
container_type Tail() const
{
// return the tail (all elements after the first element in a new instance.
}
bool IsEmpty() const
{
return true; // return whether or not this container is empty.
}
};
template <class _X>
class ContainerTypeB < _X >
{
public:
typedef _X value_type;
typedef ContainerTypeB<_X> container_type;
const _X & Head() const
{
// return head of this containers content.
}
container_type Tail() const
{
// return the tail (all elements after the first element) in a new instance.
}
bool IsEmpty() const
{
return true; // return whether or not this container is empty.
}
};
// Note: In stead of the class with static member functions, this could
// as well be a namespace with template-functions inside.
template < class _ContainerT >
class ContainerStats<_ContainerT>
{
static _ContainerT::value_type Sum(const _ContainerT & container)
{
// Implement sum - possibly in the recursive way you did in your question.
}
// more expansion functions...
};
The motivation
Let's say I'm writing a Tree class. I will represent nodes of the tree by a Tree::Node class. Methods of the class might return Tree::Node objects and take them as arguments, such as a method which gets the parent of a node: Node getParent(Node).
I'll also want a SpecialTree class. SpecialTree should extend the interface of a Tree and be usable anywhere a Tree is.
Behind the scenes, Tree and SpecialTree might have totally different implementations. For example, I might use a library's GraphA class to implement a Tree, so that Tree::Node is a thin wrapper or a typedef for a GraphA::Node. On the other hand, SpecialTree might be implemented in terms of a GraphB object, and a Tree::Node wraps a GraphB::Node.
I'll later have functions which deal with trees, like a depth-first search function. This function should accept both Tree and SpecialTree objects interchangeably.
The pattern
I will use a templated interface class to define the interface for a tree and a special tree. The template argument will be the implementation class. For example:
template <typename Implementation>
class TreeInterface
{
public:
typedef typename Implementation::Node Node;
virtual Node addNode() = 0;
virtual Node getParent(Node) = 0;
};
class TreeImplementation
{
GraphA graph;
public:
typedef GraphA::Node Node;
Node addNode() { return graph.addNode(); }
Node getParent() { // ...return the parent... }
};
class Tree : public TreeInterface<TreeImplementation>
{
TreeImplementation* impl;
public:
Tree() : impl(new TreeImplementation);
~Tree() { delete impl; }
virtual Node addNode() { return impl->addNode(); }
virtual Node getParent() { return impl->getParent(); }
};
I could then derive SpecialTreeInterface from TreeInterface:
template <typename Implementation>
class SpecialTreeInterface : public TreeInterface<Implementation>
{
virtual void specialTreeFunction() = 0;
};
And define SpecialTree and SpecialTreeImplementation analogously to Tree and TreeImplementation.
My depth-first search function might look like this:
template <typename T>
void depthFirstSearch(TreeInterface<T>& tree);
and since SpecialTree derives from TreeInterface, this will work for Tree objects and SpecialTree objects.
Alternatives
An alternative is to rely more heavily on templates so that SpecialTree isn't a descendent of TreeInterface in the type hierarchy at all. In this case, my DFS function will look like template <typename T> depthFirstSearch(T& tree). This also throws out the rigidly defined interface describing exactly what methods a Tree or its descendents should have. Since a SpecialTree should always act like a Tree, but provide some additional methods, I like the use of an interface.
Instead of the TreeInterface template parameter being the implementation, I could make it take a "representation" class that defines what a Node looks like (it will also have to define what an Arc looks like, and so on). But since I'll potentially need one of these for each of the implementations, I think I'd like to keep this together with the implementation class itself.
What do I gain by using this pattern? Mostly, a looser coupling. If I'd like to change the implementation behind Tree, SpecialTree doesn't mind at all because it only inherits the interface.
The questions
So, does this pattern have a name? I'm using the handle-body pattern by storing a pointer to ContourTreeImplementation in ContourTree. But what about the approach of having a template-ized interface? Does this have a name?
Is there a better way to do this? It does seem that I am repeating myself a lot, and writing a lot of boilerplate code, but those nested Node classes give me trouble. If Tree::Node and SpecialTree::Node had reasonably similar implementations, I could define a NodeInterface interface for a Node in TreeInterface, and override the implementation of the node class in Tree and SpecialTree. But as it is, I can't guarantee that this is true. Tree::Node may wrap a GraphA::Node, and SpecialTree::Node may wrap an integer. So this method won't quite work, but it seems like there might still be room for improvement. Any thoughts?
Looks like a mixture of the Curiously Recurring Template Pattern and the Pimpl idiom.
In the CRTP, we derive Tree from TreeInterface<Tree>; in your code you're deriving Tree from TreeInterface<TreeImplementation>. So it's also as #ElliottFrisch said: it's an application of the strategy pattern. Certain parts of the code care that Tree conforms to TreeInterface, while certain other parts care about the fact that it uses the particular strategy TreeImplementation.
Is there a better way to do this? It does seem that I am repeating myself a lot
Well, it depends what your runtime requirements are. When I look at your code, the thing that jumps out at me is that you're using virtual methods — slooooow! And your class hierarchy looks like this:
Tree is a child of
TreeInterface<TreeImplementation>
SpecialTree is a child of
TreeInterface<SpecialTreeImplementation>
Notice that the fact that TreeInterface<X>::addNode() happens to be virtual has absolutely no bearing on whether TreeInterface<Y>::addNode() is virtual! So making those methods virtual doesn't gain us any runtime polymorphism; I can't write a function that takes an arbitrary instance of TreeInterfaceBase, because we haven't got a single TreeInterfaceBase. All we've got is a bag of unrelated base classes TreeInterface<T>.
So, why do those virtual methods exist? Aha. You're using virtual to pass information from the derived class back up to the parent: the child can "see" its parent via inheritance, and the parent can "see" the child via virtual. This is the problem that is usually solved via CRTP.
So, if we used CRTP (and thus didn't need the virtual stuff anymore), we'd have just this:
template <typename Parent>
struct TreeInterface {
using Node = typename Parent::Node;
Node addNode() { return static_cast<Parent*>(this)->addNode(); }
Node getParent(Node n) const { return static_cast<Parent*>(this)->getParent(n); }
};
struct ATree : public TreeInterface<ATree> {
GraphA graph;
typedef GraphA::Node Node;
Node addNode() { return graph.addNode(); }
Node getParent(Node n) const { // ...return the parent... }
};
struct BTree : public TreeInterface<BTree> {
GraphB graph;
typedef GraphB::Node Node;
Node addNode() { return graph.addNode(); }
Node getParent(Node n) const { // ...return the parent... }
};
template <typename Implementation>
void depthFirstSearch(TreeInterface<Implementation>& tree);
At this point someone would probably remark that we don't need the ugly pointer-casting CRTP at all and we could just write
struct ATree {
GraphA graph;
typedef GraphA::Node Node;
Node addNode() { return graph.addNode(); }
Node getParent(Node n) const { // ...return the parent... }
};
struct BTree {
GraphB graph;
typedef GraphB::Node Node;
Node addNode() { return graph.addNode(); }
Node getParent(Node n) const { // ...return the parent... }
};
template <typename Tree>
void depthFirstSearch(Tree& tree);
and personally I would agree with them.
Okay, you're concerned that then there's no way of ensuring through the typesystem that the T the caller passes to depthFirstSearch actually conforms to TreeInterface. Well, I think the most C++11-ish way of enforcing that restriction would be with static_assert. For example:
template<typename Tree>
constexpr bool conforms_to_TreeInterface() {
using Node = typename Tree::Node; // we'd better have a Node typedef
static_assert(std::is_same<decltype(std::declval<Tree>().addNode()), Node>::value, "addNode() has the wrong type");
static_assert(std::is_same<decltype(std::declval<Tree>().getParent(std::declval<Node>())), Node>::value, "getParent() has the wrong type");
return true;
}
template <typename T>
void depthFirstSearch(T& tree)
{
static_assert(conforms_to_TreeInterface<T>(), "T must conform to our defined TreeInterface");
...
}
Notice that my conforms_to_TreeInterface<T>() will actually static-assert-fail if T doesn't conform; it will never actually return false. You could equally well make it return true or false and then hit the static_assert in depthFirstSearch().
Anyway, that's how I'd approach the problem. Notice that my entire post was motivated by the desire to get rid of those inefficient and confusing virtuals — someone else might latch onto a different aspect of the problem and give a totally different answer.
Here's what I'm trying to accomplish:
I'm trying to created a linked list of various types. In order to accomplish this, I figured polymorphism would be a great way to go about.
I have two classes, AttributeBase and Attribute. AttributeBase is used by AttributeSet, which just stores the start and end points of the linked list of Attribute<T>'s (as AttributeBase*'s) and does modification on the list. AttributeBase is a base class of Attribute<T> that is only in the design for the sake of making generic pointers. Attribute<T>, of course, is the specific type of AttributeBase where the actual value is stored. The main data of each Attribute<T> is an inherited string (the attribute's name, or 'key' if you will) and a value of type T.
So, thus far I have (simplified):
class AttributeBase
{
public:
AttributeBase() = delete;
AttributeBase* GetNext() { return next; };
AttributeBase* GetPrev() { return prev; };
std::string GetName() { return name; };
//Sometimes I need to get/set the value stored in a derived class
//But, how would I define the function here since the return
//type is of type T as defined in Attribute?
virtual ???? GetValue = 0;
virtual void SetValue(????) = 0;
friend class AttributeSet;
private:
AttributeBase* next = nullptr;
AttributeBase* prev = nullptr;
std::string name;
};
template <class T>
class Attribute : public AttributeBase
{
public:
Attribute( std::string _name, T _value ){ name = _name; value = _value };
T GetValue(){ return value; };
void Setvalue(T){ value = T; };
private:
T value;
};
class AttributeSet
{
public:
template <class T>
void Add(std::string,T); //Add an Attribute<T>(std::string,T) to the list
void Delete(std::string);
bool Contains(std::string _name); //Scan the list to determine if an
//attribute with name of _name exists
template <class T>
T Get(std::string); //Scan the list for 'name' and return
//AttributeBase*->GetValue()
private:
AttributeBase* start = nullptr;
AttributeBase* end = nullptr;
}
Since I tried to keep AttributeBase generic and non-templated (to avoid strongly-typed start and end pointers in AttributeSet), this brings up a problem. How do I specify an as-of-yet unspecified return type for the virtual function BaseAttribute::GetValue(). I first tried using auto, got a compile error.
Being as no instances of AttributeBase are ever actually created (and the default constructor deleted) I figured it would be possible to leave out GetValue and define it in the derived class. However, if I try *AttributeBase->GetValue() it errors out since GetValue() isn't defined in AttributeBase, only the subclasses. You would think the compiler would know that the pointer has to point to a derived class (the only derived type) since AttributeBase cannot be directly constructed.
So, in order to use GetValue() I have to know the type of the previous value ahead of time to be able to cast the AttributeBase* to an Attribute*. This would be trivial if AttributeBase itself were templated and contained a value T type. I could then just access AttributeBase*->type to determine the type of pointer I need to cast. However, like I said, templating AttributeBase destroys the intended use of the object.
More than likely, I'm going about this in a completely wrong way (yet again). But at this point I am stuck for ideas. Any help would be appreciated!
So a truly general solution doesn't exist. You just can't get any arbitrary type from a base class because all your overrides of your base class virtual function have to have the same return type.
That leaves you two options.
First, you can decide in advance that you're going to have your list hold any object that derives from some common base type. This will severely limit what you can put into your list, but at least you have full freedom with those objects once they're there.
Second, depending on what you want to actually do with the objects once they're in your list, you can look at the new Boost.TypeErasure library. If all you need to do with list is, say, output them all, or some either small amount of operations, this can help you get there.
Since the signatures of GetValue and SetValue depend on a type, they need to be templates. But they can be template members without requiring a class template.
class AttributeBase
{
public:
template <typename T> T GetValue() const;
template <typename T> void SetValue(T);
//...
};
template <typename T>
T AttributeBase::GetValue() const
{
return dynamic_cast<Attribute<T>&>(*this).GetValue();
}
template <typename T>
void AttributeBase::SetValue(T val)
{
dynamic_cast<Attribute<T>&>(*this).SetValue(val);
}
template <typename T>
T AttributeSet::Get(std::string const& name) const
{
// (assuming a private helper method Find().)
const AttributeBase* attr = Find(name);
if ( !attr )
throw std::invalid_argument("attribute not in set");
return attr->GetValue<T>();
}
One gotcha, though: these functions will all throw an exception if you happen to use the wrong type. And SetValue might automatically deduce its template argument, and might do so incorrectly. For example, if a is a AttributeBase& reference which is really an Attribute<long int>, then a.SetValue(1) is the same as a.SetValue<int>(1), which will throw. The correct expression would be a.SetValue<long int>(1) (or a.SetValue(1L), but I'd prefer the explicit template argument).
So suppose I have a tree class like this in c++
class Node{
void addChild(Node*);
/*obvious stuff*/
protected:
Node* parent;
vector<Node*> children
}
class specialNode : public Node{
void addChild(specialNode*);
/*obvious stuff*/
/*special stuff*/
}
Now whenever I access the children in specialTree, I obviously get Node*, not specialNode*.
But this specialNode* has member variables and functions that Node doesn't have.
I can force specialNode to only have take specialNode as children and otherwise break in compile time,
but I still get Node* when accessing children/parent, and I have to cast it whenever I want to use special functions, even in specialNode functions.
Is there any clever, or just any better way to go about this?
Other than literally casting every time?
If you only need SpecialNode objects in your tree (and just want to encapsulate all generic tree functionality in Node) you can make Node a so called "mix-in" class like
template <class N>
class Node : public N {
public:
void addChild(Node<N>*);
protected:
Node<N>* parent;
vector<Node<N>*> children;
};
class SpecialNodeBase {
// Here comes all "special" data/methods for your "special" tree
};
typedef Node<SpecialNodeBase> SpecialNode;
After that you can construct a tree of SpecialNode objects and use all methods from SpecialNodeBase as well as additional tree-managing functions from Node
Because addChild function in your child class is not polymorphism, make it virtual, but overloading functions across base/child members is not allowed, so we have to change the addChild parameter in the child class:
class Node{
virtual void addChild(Node*);
...
}
class specialNode : public Node{
virtual void addChild(Node*);
...
}
Now, it should work.
If you want to access to the childeren variable from the child class (specialNode class), you should cast it. For example:
specialNode* var = static_cast<specialNode*>(children[i]);
Since we declared addChild as a virtual function, then we should use dynamic_cast instead of static_cast if we aren't sure that children[i] is always an instance of specialNode class, and thus it is better to use dynamic_cast:
specialNode* var = dynamic_cast<specialNode*>(children[i]);
if(var != NULL)
{
//...
}
If I understand correctly, the "Mix-in" class solution won't allow you to call addChild from functions implemented by SpecialNodeBaseClass.
You can actually do the following:
template <class recursiveT>
class Base {
public:
Base(dataType data) { populate children with data; }
void addChild() { something base class appropriate; }
protected:
std::vector<recursiveT> children;
};
class Derived: public Base<Derived> {
public:
/* note: the constructor here will actually call the
constuctor of the base class */
Derived(dataType data) : Base<Derived>(data) {}
/* other special functions go here. */
};
This may look a little crazy, but it compiles cleanly for me on several GCC versions so I'm inclined to believe it's not totally wrong-headed. You should now be able to call the functions of Base from inside Derived.
You will definitely have to cast the Node * to a specialNode * at some point, but you can make this clean and easy to manage by doing this in only one place. You could add a member function, say getParent and override it in specialNode, like this:
class Node {
...
virtual Node *getParent() {
return parent;
}
};
class specialNode : public Node {
...
specialNode *getParent() {
return dynamic_cast<specialNode *>(parent);
}
};
Of course, this is assuming that specialNodes always have other specialNodes as parent/children. If you mix Nodes and specialNodes, this obviously won't work.