Here is a sample code:
class Base {
public:
virtual void common();
};
class Derived {
public:
void common();
virtual void spec(); // added function specific for this class
};
class BaseTracker {
public:
void add(Base* p);
private:
vector < Base* > vec;
};
class DerivedTracker {
public:
void add(Derived* p);
private:
vector < Derived* > vec;
};
I want DerivedTracker and BaseTracker to be derived from class Tracker, because a lot of code for these two classes is the same, except one method, add(). DerivedTracker::add() method needs to call functions specific to Derived class. But I don't want to do dynamic casting. I think it is not the case when I should use it. Also Tracker class should include container, so functions which are implemented in this class could use it.
It sounds like the Tracker class would best be a template instead of being derived from a common ancestor:
template<typename Element>
class Tracker {
public:
void add(Element* p);
private:
vector< Element* > vec;
};
typedef Tracker<Base> BaseTracker;
typedef Tracker<Derived> DerivedTracker;
You could then add a specialization of the add() method that uses Derived's special features:
template<>
void Tracker<Derived>::add(Derived* p) {
p->spec();
vec.push_back(p);
}
Related
I have a sprite class, which has a templatised data member. It holds an object, which has a pointer to this specialised sprite template class.
That object requires a forward declaration of my sprite class, but since sprite is a template class, I need to include the full header. Therefore I get a cyclic dependancy which I am unable to figure out
Sprite.h
#include "myclass.h"
template<typename SpriteType, typename = typename std::enable_if_t<std::is_base_of_v<sf::Transformable, SpriteType> && std::is_base_of_v<sf::Drawable, SpriteType>>>
class Sprite {
public:
SpriteType s;
myclass<SpriteType>;
Sprite() {
}
auto foo() {
return s;
}
private:
};
myclass.h
#include "Sprite.h"
//a sprite of type T, is going to create a myclass<Sprite<T>>, a pointer of the Sprite<T> is held in myclass.
template<typename T>
class myclass
{
public:
std::shared_ptr<Sprite<T>> ptr;
myclass() {
}
private:
};
How could I solve this cyclic dependency?
So in summary:
-Sprite is a template class.
-Sprite holds an object to another class. This other class holds a pointer to my this templated sprite class.
-This gives me a cyclic dependency, since both classes are now templates, and need to have their implementations written in their header files.
Simplified decoupling, based on #Taekahns solution.
template<typename T>
class myclass
{
public:
std::shared_ptr<T> ptr;
myclass() {
}
private:
};
template<typename SpriteType, typename = typename std::enable_if_t<std::is_base_of_v<sf::Transformable, SpriteType> && std::is_base_of_v<sf::Drawable, SpriteType>>>
class Sprite {
public:
SpriteType s;
// DO NOT PASS SpriteType here, put the whole Sprite<SpriteType>
myclass<Sprite<SpriteType>> t;
Sprite() {
}
auto foo() {
return s;
}
private:
};
One of the great thing about templates is breaking type dependencies.
You could do something like this. Simplified for readability.
template<typename T>
class myclass
{
public:
std::shared_ptr<T> ptr;
myclass() {
}
private:
};
template<typename SpriteType, typename = std::enable_if_t<std::is_base_of_v<base_class, SpriteType>>>
class Sprite {
public:
SpriteType s;
myclass<Sprite<SpriteType>> t;
Sprite() {
}
auto foo() {
return s;
}
private:
};
That is one of many options.
Another option is to use an interface. i.e. a pure virtual base class that isn't a template.
Example:
I think something like this should do it. Starting to get a hard to follow though.
class base_sprite
{
public:
virtual ~base_sprite(){};
virtual int foo() = 0;
};
template<typename T>
class myclass
{
public:
std::shared_ptr<base_sprite> ptr;
myclass() : ptr(std::make_shared<T>())
{
};
};
template<typename SpriteType>
class Sprite : public base_sprite{
public:
myclass<Sprite<SpriteType>> l;
int foo() override {return 0;};
};
I am trying to define a graph, where the vertex class is defined with a template. How do I then define a pointer to this templated vertex in another class.
template<class T1, class T2>
class Vertex {
public:
virtual T1 run(T2) = 0;
};
class Graph {
std::map<std::string, Vertex*> vertices; // <--- How do I do something like this
int** adjacency_matrix;
public:
void run() {
...
}
};
I have been looking at some other questions on Stack-Overflow, the common suggestion seems to be to use a base class that is not templated, and use the pointers for that and putting the common functions in that class.
However, in my code, the function run() which is the common one and uses the template for the return type. So I do not understand how to use the base class.
Any ideas?
There is no class named Vertex, only a template for classes.
The simple way out is using polymorphism, as you only store pointers anyway:
Define a base-class all Vertex instances (specialized or not) inherit from.
template<class T1, class T2>
class Vertex : VertexBase {
public:
virtual T1 run(T2) = 0;
};
struct VertexBase {
~VertexBase() = default;
template<class T1, class T2> T1 run(T2 x) {
return dynamic_cast<Vertex<T1,T2>&>(*this).run(x);
}
};
Anyway, also take a look at std::function and see whether that solves your problem well enough.
First, as I said, you need a non-template base class from which Vertex inherits:
struct Base
{
virtual ~Base() = default;
};
template<class T1, class T2>
class Vertex : public Base
{
public:
virtual T1 run(T2) = 0;
};
Then inside your Graph function you use std::shared_ptr<Base> instead of Vertex*:
class Graph {
std::map<std::string, std::shared_ptr<Base>> vertices;
public:
void run();
};
Now when calling run() on the Vertex pointer, you need to dynamic_cast the pointer back the appropriate derived class. In your case you can't actually call run() on a Vertex* since Vertex::run() is a pure virtual function.
int main()
{
Graph g;
g.vertices["xyz"] = std::make_shared<Vertex<int, int>>();
// error: field type 'Vertex<int, int>' is an abstract class
}
If you want to call Vertex, either make run() a non pure-virtual function and give it an implementation, or use a derived class for the implementation:
class Derived : public Vertex<int, int>
{
public:
int run(int n) { std::cout << n << '\n'; return 0; }
};
class Graph {
std::map<std::string, std::shared_ptr<Base>> vertices;
public:
template<class T2>
void call_run(std::shared_ptr<Base> p, T2 value)
{
if (auto derived = std::dynamic_pointer_cast<Derived>(p))
derived->run(value);
if (/* other derived classes... */);
}
void run();
};
You can either specify a type like this:
std::map<std::string, Vertex<int, int>*> vertices;
Or make Graph templated as well:
template<class T1, class T2>
class Graph {
std::map<std::string, Vertex<T1, T2>*> vertices;
template <class CollectionItem>
class Collection
{
void A();
// Many other utility functions
}
class ICollection
{
virtual void B() = 0;
}
class Base : public Collection<BaseItem>, public IBase
{
virtual void B();
}
Is there any way of offering Collection functions via ICollection interface without wrapping all the functions in Base class? ICollection : public Collection<CollectionItem> is not an option.
Bounty Update:
OK, so the original idea was to have Interface to all Collection classes. Before we continue, every CollectionItem also has Interface, let's call it ICollectionItem and ICollection only knows about ICollectionItem.
So what I did was create another template class as Interface to Collection template class - ICollection (pure virtual) accepting ICollectionItem(s). Collection class inherits this interface.
Every Collection class (inheriting Collection<CollectionItem> class) would also inherit it's Interface Collection class. That Interface then virtual inherits ICollection<ICollectionItem>. I'll just post the code :)
Here is the code:
template <class ICollectionItem>
class ICollection
{
public:
virtual const ICollectionItem* At(const int idx) = 0;
};
template <class CollectionItem, class ICollectionItem>
class Collection
: public ICollection,
public virtual ICollection<ICollectionItem> // Weak point
{
private:
List<CollectionItem*> fContainer;
public:
Collection(void) {}
virtual ~Collection() {}
virtual const ICollectionItem* At(const int idx); // Casting GetAt result
virtual const TCollectionItem& GetAt(const int idx) const
virtual ListIterator<TCollectionItem> >* GetIterator(void) const;
virtual ListIterator<ICollectionItem> >* Iterator(void) const; // Weak point
}
Example usage:
class IBaseItem
{
public:
virtual int Number() = 0;
{
class BaseItem
: public IBaseItem
{
public:
virtual int Number();
void SetNumber(int value);
}
class IBase
: public virtual ICollection<IBaseItem>
{
public:
virtual IBaseItem* ItemByName(String name) = 0;
virtual ~IBase() {}
}
class Base
: public Collection<BaseItem, IBaseItem>,
public IBase
{
public:
BaseItem* GetItemByName(String name);
virtual IBaseItem* ItemByName(String name);
}
Weak points:
First is at using virtual inheritance ... lots written about it, not much to talk about, or is it?
Unable to access Iterator using ICollection interface. See ListIterator function, only first one can be implemented, the second one would require some kind of new List of IBaseItem. I decided to live with that and just use for loop.
Even tho I somehow managed to get what I wanted (With wrapping and casting), I would still like to hear an second opinion. I don't like using virtual inheritance, specially in such delicate situations - using Collections for application Base creation.
I can not see any other solution than calling some Collection method in Base implementation of IBase virtual methods.
class Base : public Collection<BaseItem>, public IBase
{
virtual void B()
{
A();
}
}
You say, and I quote:
I want to call Collection functions using IBase pointer
I really don't see what is to be done here besides dynamic_cast. It does exactly what you want it to do.
void fun(IBase * base) {
auto * coll = dynamic_cast<Collection<BaseItem>*>(base);
if (coll) {
coll->A();
}
}
Your Collection class must have a virtual destructor.
You can, of course, offer a templated version, if you'd need different baseitems in different, scenarios for some reasons. This has bad code smell and I think your architecture is bad at this point, but oh well.
template <typename T> void fun(IBase * base) {
auto * coll = dynamic_cast<Collection<T>*>(base);
if (coll) {
coll->A();
}
}
void test(IBase * p) {
fun<BaseItem5>(p);
}
If you have some other specific scenario in mind, please edit your question to say what you mean.
Hmm...So you wanna to reuse the Collection class's utility functions, and you want to design a class which will implement an interface defined by IBase. As you mentioned above,"wrapping all the functions in Base class" is a way to offer Collection functions.
(1) Via inheritance,derived class has a good knowledge of Collection
class Derived:public Collection<DerivedType>,public IBase{};
or
template <typename T>
class Derived:public Collection<T>,public IBase{};
(2) Via inheritance,derived class knows little about Collection,but through IBase
class IBase : public Collection<BaseItem>{};
class Derived:public IBase{};
By (1),If you want to call Collection functions using IBase pointer,you have to wrap the functions.
By (2), any Derived instance is " a kind of " IBase which is "a kind of " Collection. So you can use IBase pointer to call Collection functions.
So,the key point is that the objects pointed by the IBase pointer should have the method you want to call.Wrap it or inherit it. I can not see any other solution than these two ways.
Edit: the idea is refined based on your example:
Here is an idea:
//generic interface can be kept as it is
template <class ICollectionItem>
class ICollection
{
public:
virtual const ICollectionItem* At(const int idx) = 0;
};
class Empty
{
};
template <class CollectionItem , class BaseClass = Empty>
class GenericCollection
: public BaseClass
{
public:
const CollectionItem* At(const int idx);
// At and ItemByName are standard functions for a collection
CollectionItem* ItemByName(String name);
//note that here nothing has to be declared as virtual
};
//example usage:
class IBase
: public virtual ICollection<IBaseItem>
{
public:
virtual IBaseItem* ItemByName(String name) = 0;
virtual ~IBase() {}
};
class Base
: public GenericCollection<BaseItem, IBase >
{
public:
//nothing to be implemented here, all functions are implemented in GenericCollection and defined as virtual in IBase
//The definition of the functions has to be the same:
};
In collection you can implement whatever and in the interface you can define what ever you want to be virtual from your collection. The only thing is that you need to have some standard in naming convention for functions.
Hope this helps,
Raxvan.
From your comments in another answer, it seems you want a collection of interfaces, and an implementation of this interface. The simplest I can advise you is the following:
template<typename T>
class ICollection
{
public:
virtual iterator<T>* begin() const = 0;
};
template<typename T, typename TBase>
class Collection : public ICollection<TBase>
{
public:
iterator_impl<T>* begin() const { return whatever; }
};
Example:
class IItem {};
class Item : public IItem {};
class Base : public Collection<Item, IItem> {};
old answer:
Is there any way of offering Collection functions via IBase interface without wrapping all the functions in Base class ?
If I understood your problem, you want to use it like this:
void myfunc()
{
// ...
IBase* obj = ...;
obj->A();
obj->B();
}
I think here is a misunderstanding here: if you want A() to be callable from an IBase, then you have to add it to Ibase declaration.
If you want to use the Collection functions on an object, then you should cast this object to a Collection, via dynamic_cast for example.
Furthermore, if you have such a funcion:
void fun(IBase* base) { /* ... */ }
you cannot cast to a Collection*, since there are no relationship between these two classes, unless you have another way to be sure base is a Collection:
void fun(IBase* base)
{
if(base && base->isABaseItemCollection())
{
// Valid, since the real type was checked before
Collection* collection = (Collection*)base;
// ...
}
}
On a side note: you can generate bases almost automatically:
template
class Base : public Collection, public U {};
typedef Base BaseCollection;
According to comment/chat:
You have something like:
class IAnimal { /*...*/ };
class Cat : public IAnimal { /*...*/ };
class Dog : public IAnimal { /*...*/ };
class Cats
{
std::vector<Cat*> cats;
public:
Cat* at(size_t index) { return cats[index]; }
/*...*/
};
class Dogs
{
std::vector<Dog*> dogs;
public:
Dog* at(size_t index) { return dogs[index]; }
/*...*/
};
And you want to factorize some code using something like
class IAnimals
{
public:
std::vector<IAnimals*> animals; // or getter/setter which works with IAnimals.
/* some common factorized code */
};
// And so
class Cats : public IAnimals { /**/ };
class Dogs : public IAnimals { /**/ };
I propose, instead of creating class IAnimals, to use template functions as:
template <typename TAnimals>
void foo(TAnimals& animals)
{
Ianimals* animal = animals.at(42);
// ...
animal->eat(food);
// ...
}
You have to give compatible "interface" (names) to the type used in template.
Maybe you could have an operator() in IBase that would be delegated to Base?
class CollectionBase {};
template <class Item> class Collection: public CollectionBase {};
class IBase
{
public:
virtual CollectionBase* operator()() = 0;
};
class Base : public Collection<BaseItem>, public IBase
{
public:
virtual Collection<BaseItem>* operator()() { return this; }
};
I want to make a class with a member function that takes a reference to another class, where both classes are derived from abstract classes. I get a compiler error that the class Container is abstract because it doesn't implement addElem().
class Ielem
{
public:
virtual void action() = 0;
};
class Elem: public Ielem
{
public:
void action() {};
void extra() {};
};
class Icontainer
{
public:
virtual void addElem(Ielem &elem) = 0;
};
class Container: public Icontainer
{
public:
void addElem(Elem &elem) { elem.extra(); };
};
int main(int argc, char* argv[])
{
Elem e;
Container c;
c.addElem(e);
return 0;
}
It seems like this ought to work, because any reference to an Elem is also a reference to an Ielem. It compiles if I make Container::addElem take a reference to an Ielem. But then Container::addElem() can't call Elem::extra() unless I use dynamic_cast, which isn't available on the embedded compiler I'm using, or a regular cast, which isn't type safe.
Suggestions?
It's the wrong way round: the base class Icontainer specifies that addElem can take any Ielem object as an argument, but in your derived class you accept only Elem. This is a "narrower" type, so the contract "I'll accept any Ielem you throw at me" specified in the base class is violated.
I think templates would be the solution here. You don't even need the base classes anymore. Something like this:
class Elem
{
public:
void action() {};
void extra() {};
};
template<typename ElemType>
class Container
{
public:
void addElem(ElemType &elem) { elem.extra(); };
};
int main(int argc, char* argv[])
{
Elem e;
Container<Elem> c;
c.addElem(e);
return 0;
}
As a bonus, you can now use Container with any type that has an extra() function, and it will just work.
The problem is simply that your virtual method doesn't have the same signature as the concrete method which is intended to overload it; so the compiler sees it as a different function entirely and complains because you haven't implemented void addElem(Ielem &elem). This is one solution, which you probably don't want--
class Icontainer
{
public:
virtual void addElem(Elem &elem) = 0; //Ielem -> Elem
};
It depends on all your other constraints but I think what I would do--and what seems to conform to general design guidelines, e.g. Sutter & Alexandreascu, would be to create an intermediate abstract class with the full interface--
class Melem: public Ielem
{
public:
// void action() {}; //Already have this form Ielem
void extra() = 0;
};
and then
class Icontainer
{
public:
virtual void addElem(Melem &elem) = 0;
};
class Container: public Icontainer
{
public:
void addElem(Melem &elem) { elem.extra(); };
//*Now* we're implementing Icontainer::addElem
};
I've been looking at factory method and struggled to find a solution to my problem (although i have the feeling it is straight forward.I'm trying to create objects that come from the same derived class, which is know in advance but they have different parameters.
class Base
{
public:
Base(){};
~Base(){};
std::string name;
double base_input;
double output;
virtual void relation_function()=0;
};
class Derived1 : public Base
{
public:
double private_input;
int multiplier;
Derived1(std::string , double , double , int);
~Derived1(){};
virtual void relation_function();
};
class Derived2 : public Base
{
public:
double private_input;
int multiplier;
Derived2(std::string , double , int);
~Derived2(){};
virtual void relation_function();
};
the parameters are injected in the derived class based on their constructors.
Derived1::Derived1(std::string input_name, double input_base_input,double input_private_input,
int input_multiplier){
name=input_name;
base_input=input_base_input;
private_input=input_private_input;
multiplier=input_multiplier;
};
Derived2::Derived2(std::string input_name,double input_private_input,int input_multiplier)
{
name=input_name;
private_input=input_private_input;
multiplier=input_multiplier;
void relation_function();};
void Derived2:: relation_function(){output=multiplier*private_input;};
void Derived1:: relation_function(){output=multiplier*base_input*private_input;};
Currently i'm creating instance of the derived class manually as follows
std::vector<std::string> v(3);
v[0]="a";v[1]="b";v[2]="c";
for (int n=0;n<=2;n++)
Base* pderived1(new Derived1(v[n],2,2,1));
std::vector<std::string> v(2);
v[0]="d";v[1]="e";
for (int n=0;n<=1;n++)
Base* pderived1(new Derived1(v[n],5,9,9));
which is not ideal, i need to create first a pointer to the constructor of the derived class to "fix"/"freeze" some of the paramters in the constructor functions before a number of instances are created from each derived class.
base* (*pconstructor){string, double, double, int) = Derived (string, 2,2,1)
the aim is to use this pointer to the constructor as the main tool to dicate the paramaters before passing to the following functions to create the object. the function below would act as a factory to create the number of instances/objects required from derived1 or derived which may have different parameters in their constructor functions like derived2.
base* function(std::vector<string>){ create instances.. }
i dont know how to create the pointer to manipulate the constructor parameters nor the function that would be used to create the instances.. Any clues, please..
Thanks you all in advance for your help from a c++ novice!
From the question, it's unclear that what's the actual goal. However, I am not aware if you can have a pointer to member function for constructor / destructor. So you have to give up for that option.
It's better to do whatever check while constructor instance itself. Also following is a bad bad idea, as it leaks memory:
for (int n=0;n<=1;n++)
Base* pderived1(new Derived1(v[n],5,9,9));
You are overwriting pderived1 more than once. Cautious with use of new/malloc.
good solution to this problem is just providing functions with different parameters:
#include <string>
#include <typeinfo>
#include <vector>
class FactoryFunction;
class Factory {
public:
template<class T, class P1, class P2>
void reg2(T (*fptr)(P1, P2));
template<class T, class P1, class P2, class P3>
void reg3(T (*fptr)(P1,P2,P3));
template<class T, class P1, class P2, class P3, class P4>
void reg4(T (*fptr)(P1,P2,P3,P4));
private:
std::vector<FactoryFunction*> vec;
};
Base *derived1_factory(std::string s, double d1, double d2, int i)
{
return new Derived1(s,d1,d2,i);
}
int main() {
Factory f;
f.reg4(&derived1_factory);
}
Edit: This design also requires some stuff that might be difficult to figure out, in particular the following classes:
class FactoryFunction {
public:
virtual int NumParams() const=0;
virtual void set_parameter(int i, void *p)=0;
virtual std::string parameter_type(int i) const=0;
virtual void *return_value() const=0;
virtual std::string return_type() const=0;
};
template<class T, class P1>
class FactoryFunction1 : public FactoryFunction
{
public:
FactoryFunction1(T (*fptr)(P1)) : fptr(fptr) { }
int NumParams() const { return 1; }
void set_parameter(int i, void *p) { switch(i) { case 0: param1 =*(P1*)p; break; }; }
std::string parameter_type(int i) const { switch(i) { case 0: return typeid(P1).name(); }; }
void *return_value(int i) const { return_val = fptr(param1); return (void*)&return_val; }
std::string return_type() const { return typeid(T).name(); }
private:
T (*fptr)(P1);
T return_val;
P1 param1;
};
Then a function like reg1 could be implemented to store new FactoryFunction1<T,P1>(fptr) to a std::vector<FactoryFunction*>.
Obviously reg1/reg2/reg3 functions can have std::string as a parameter too.
Edit: oh, reg4 is just missing implementation (you need to implement other functinons too).
template<class T, class P1, class P2, class P3, class P4>
void Factory::reg4(T (*fptr)(P1,P2,P3,P4))
{
vec.push_back(new FactoryFunction4(fptr));
}
Lets hope it compiles now :)