I have a design problem. I'm asked to plan a design for a certain problem, where I need a few lists, and also a queue (which I need to create by myself, STL isn't allowed). In order to make the implementation more efficient, I thought about creating a generic list as follows: Create a node which contains a pointer to 'Data', an empty class. Then, any class that I want to make a list or a queue of (is the last sentence grammatically correct?), I'll just make it a subclass of data. That's the only way to make a generic list (I think), as we are not allowed to use void*.
The problem begins when I want to use a certain method of a certain class in a certain list. I can't do that, since 'Data' doesn't know that function. Creating a virtual function in Data is counter-logical and ugly, and we're also not allowed to use any downcasting.
Is there a way to overcome the problem using generic ADTs? Or must I create specific lists?
Thank you very much!
edit: We are also not allowed to use templates.
About the list and the queue, maybe you can adopt the same approach taken by the STL: just create the list, and then stack, as an adaptor of the list in which you only push and pop from the end.
About those contraints, which seems to be draconian, don't I suppose that the objective is for you to use templates?
Instead of creating and empty class, which if does not contain any method does not serve you at all, use a template as in the following example:
template<typename T>
class List {
class Node {
public:
Node(T* d)
{ data.reset( new Data( d ) ); }
T * getData()
{ return data; }
Node * getSig()
{ return sig; }
private:
std::auto_ptr<T> data;
Node * sig;
};
List()...
// Lots of more things...
};
You can find more info here:
http://www.cplusplus.com/doc/tutorial/templates/
Hope this helps.
Related
I have a tree class that includes data members and member functions that operate on the data of children:
class Tree {
// variables, member functions here
Tree *parent;
std::vector<Tree*> children;
public:
Tree(Tree* parent, int par0 /*, other constructor parameters*/) {
//....
this->parent = parent;
for (int n = 0; n < par0; n++)
children.push_back(new Tree(this, /*other arguments*/));
//...
}
void method() {
for (auto node: children)
node->method();
if (children.size() == 0) {
// Code for leaf nodes
} else {
// Code for internal nodes
}
}
};
The Tree constructor creates the tree structure, allocating and initializing every node according to the arguments.
I would like to add new data and functions to the class, resulting in the new class ExtTree, which has access to all data and functions of Tree, and shares as much code with it as possible. However, in ExtTree both the parents and the children should be (ExtTree*) rather than (Tree*). How can I reorganize this code so that ExtTree would just add its own new data, and fall back on Tree for the old methods?
A related question was asked 4 years ago here, but I could not work out the solution based on the answers in that; in particular, how ExtTree would call the base constructor, or how it can access Tree::method().
You will get the best, most type-safe result by converting the whole thing to a template.
It is possible to come up with a non-template based solution, but I don't think it's going to be optimal. I am suggesting a template-based solution but, if for whatever reason, a template is not going to cut it, you might get acceptable results with the following approach:
A) Define a virtual method: ExtTree *get_extree(). Tree::get_extree() either returns nullptr or throws an exception (up to you, whichever works best for your application). ExtTree::get_extree() returns this.
B) Define another virtual method called create_node(). Tree::create_node() executes new Tree( /* forwarded parameters */), and ExtTree::create_node() executes new ExtTree( /* forwarded parameters */).
C) Replace all of your existing new Tree calls with a call to create_node(), instead.
D) And any other common code laying reason that needs to work with both Trees and ExtTrees will use get_extree() to figure out what it's working with.
This will, more or less, get you where you want to go, mostly. A) is little different from, conceptually, just using a dynamic_cast(), and there's nothing wrong with using a dynamic_cast in lieu of get_extree(). But sometimes you can come across someone having an allergy to dynamic_cast, and this would be one way to avoid it.
I don't think there's really a perfect, 100% clean, non-template based solution here. It might be possible to get a 100% type-safe solution here by creating a much larger pile of virtual methods, and implementing pretty much everything as a virtual method.
But, I think it's going to be a lot of work. This is really what templates are for. Use them.
I'm sure this has been answered many times, but I don't know how to search for this. Is this polymorphism? Overloading?
Basically I want to take a vector, and modify its functions the way I want them or create new ones.
E.g: I want push_back() to insert an element and keep the vector in descending order. So the addition would be to swap() the element to its respective place. Or I would like to add a new function pop_front().
That being said, I need it as a member function, e.g:
vector<int> x;
x.pop_front();
not:
pop_front(x);
Is this ever done in practice? I know I can just use existing containers, like a priority queue for my example, but I'd rather make completely custom functions.
Basically, std::vector is not designed to be base class, inherit from it would be a bad idea in general. For example its dtor is not virtual.
It's better to use composition here. e.g.
template <typename T>
class MyVector {
private:
std::vector<T> v;
public:
void pop_front() {
// processing on v ...
}
};
Say I have two different objects that are completely different, Sprite and PhysicsData.
I write an empty base class and a container class that can push and remove objects to/from a container.
I create two of these containers to store the two different objects - Sprite and PhysicsData.
(Different objects aren't together in the same class)
class base
{
};
class ContainerManager
{
public:
std::vector<base*> list;
void Push(base *object);
void Remove(base *object);
};
class PhysicsData : public base
{
void applyGravity();
};
class Sprite : public base
{
void Draw();
};
ContainerManager SpriteContainer;
ContainerManager PhysicsDataContainer;
Sprite aSprite;
SpriteContainer.Push(&aSprite);
PhysicsData SomeData;
PhysicsDataContainer.Push(&SomeData);
Is this the way that this should bet done?
This is not a C++ way. You should use templates.
For you to know, STL (which you are calling to when using std:: namespace prefix) is, actually, Standard Template Library :). A lot of template classes are already there, e.g. for the push / remove operations see std::list<T>
You use it like this:
std::list<Sprite> SpriteContainer;
std::list<PhysicsData> PhysicsDataContainer;
and so on.
There is a cool guide about C++ templates, if you still want to do your own class for some more functionality.
And there is a reference to std::list, (i don't think i need to explain the usage of std::vector for you) if the question was the actual thing you've wanted to do.
You're having Templates in C++ and still worrying about having a common base class for a trivial container??
template <class T>
class Container{
private:
vector<T> list;
public:
void Push(T data);
T Pop();
};
If you put a single virtual function into the base class, you'll be able to use dynamic_cast to get back the proper pointer if you mix different types in the same container. A virtual destructor would be a good idea because then you could delete the object if it were dynamically allocated, without having to cast it back to the original pointer.
If you're not going to mix types within a single container, I agree with dreamzor that a template class would be better. That's the way all the standard containers are implemented.
That looks like technically correct code but you are not doing any type checking. So as you can see PhysicsData is showing up in your SpriteContainer. You probably do not want this.
There is more than one way to keep PhysicsData out of your SpriteContainer. One way is to use templates. With templates you would state what type of base objects the container should work with at compile time.
Another method is to inherit from your ContainerManager two types of ContainerManagers, one called PhysicsContainerManager and one called SpriteContainerManager. These two child classes can do type check to verify that the objects being passed are in fact either a SpriteContainer or a PhisicsData. This link shows how to do type check in c++ C++ equivalent of instanceof
thanks
jose
I've made BSTs before. Can I use this to make a BST without modifications?
template <class Item>
class binary_tree_node
{
public:
private:
Item data_field;
binary_tree_node *left_ptr;
binary_tree_node *right_ptr;
};
I tried making a BST with this but ran into some problems. For one thing, when I create the root node, I can't access the pointers to its child nodes.
No, you won't be able to make a BST with a class that says "place public member functions here".
It won't even compile without some pretty hacky typedefs and macros.
Without modifications, no.
But that line 'place public member functions here' is screaming out that you should be modifying it.
Since you talk about permission problem, it means you are trying to use free functions. But since the pointers are private, you won't have access to them.
What you should be doing is creating member functions. For example:
class binary_tree_node
{
public:
binary_tree_node()
{
}
bool is_item_in_tree(const Item &item)
{
}
...
};
Anyway, I'd recommend reviewing your C++ basics around visibility and OOP.
Normally,you should provide the comparation interface for the new Item class,becuase in the insert and remove opeartion,the comparation are needed.
The concrete information was not given,so I do not know whether you use < and > etc relation operators or not.But If you use them.You should make sure the new Item class support these operators.
I'd advice you to add one generic comparation class name Comp to provide the compration interface for the Item class.
My C++ framework has Buttons. A Button derives from Control. So a function accepting a Control can take a Button as its argument. So far so good.
I also have List<T>. However, List<Button> doesn't derive from List<Control>, which means a function accepting a list of Controls can't take a list of Buttons as its argument. This is unfortunate.
Maybe this is a stupid question, but I don't see how can I solve this :( List<Button> should derive from List<Control>, but I don't see a way to make this happen "automatically".
Stroustrup has an item on this in his FAQ:
Why can't I assign a vector<Apple*> to a vector<Fruit*>
You can solve it in two ways:
Make the List contain pointers to Control . Then accept List<Control*>
Make your function a template. You can still use List<Button> and List<Control> then, but it's more boilerplate code, and not necassary most of the time.
Here is code for the second alternative. The first alternative is already explained by other answers:
class MyWindow {
template<typename T>
void doSomething(List<T> & l) {
// do something with the list...
if(boost::is_same<Control, T>::value) {
// special casing Control
} else if(boost::is_same<Button, T>::value) {
// special casing Button
}
}
};
To restrict doSomething only for List<derived from Control>, some more code is needed (look for enable_if if you want to know).
Note that this kind of code (looking what type you have) is rather to avoid. You should handle such things with virtual functions. Add a function doSomething to Control, and override it in Button.
I hate to tell you but if you're using a list of instances to Control instead of pointers to Control, your buttons will be garbage anyway (Google "object slicing"). If they're lists of pointers, then either make the list<button*> into list<control*> as others have suggested, or do a copy to a new list<control*> from the list<button*> and pass that into the function instead. Or rewrite the function as a template.
So if you previously had a function called doSomething that took a list of controls as an argument, you'd rewrite it as:
template <class TControl>
void doSomething( const std::list<TControl*>& myControls ) {
... whatever the function is currently doing ...
}
void doSomethingElse() {
std::list<Button*> buttons;
std::list<Control*> controls;
doSomething( buttons );
doSomething( controls );
}
How about using pointers? Just have a list of list<Control*> and put whatever Control-derived objects you like into it.
Instead of using List<Button>, use List<Control*>, which are pointing to Buttons.This way, your function only has to take one type: List<Control*>.
Generally, the C++ way to write algorithms that perform on a list, sequence, ... is to provide iterators as arguments.
template < class iterator >
doSomething(iterator beg, iterator end);
This solves the List< Button* > is not derived from List< Control* >. (using a template List< T* > would too, but that's kind of making your function generic-but-not-really)
In my experience, making good templatized functions operating on iterators can be a lot of (too much...) work, but it's the "C++ way"...
If you go this route, consider using Boost.ConceptCheck. It'll make your life a lot easier.