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;};
};
Related
I have the following classes:
class Box{...};
class MyBox : public Box{...};
And the template:
template <type T>
class ObjectManager{...};
Which I use in some other class:
class Engine{
ObjectManager<Box> * manager = nullptr;
...
};
Then I extend (implement) the Engine interface:
class MyEngine : public Engine{...}
And in that implementation (not earlier!) I know that manager should be like that:
MyEngine::MyEngine(){
manager = new ObjectManager<MyBox>();
}
But this gives me an error because of types conflict (conversion between ObjectManager<Box> and ObjectManager<MyBox>), even when MyBox inherits from Box.
Is there any way around that problem? I don't want to modify the Box, MyBox, ObjectManager and Engine classes.
Templatize Engine and then inherit MyEngine with Engine carrying the template instance of Box that you desire. Something like this: (http://codepad.org/SZMSbCRB)
#include <iostream>
using namespace std;
class Box{
};
class MyBox : public Box{
};
template <typename T>
class ObjectManager{
};
template <typename T>
class Engine{
public:
ObjectManager<T*> * manager;
};
class MyEngine : public Engine<MyBox>{
public:
MyEngine(){
manager = new ObjectManager<MyBox*>();
cout<<"myEngine created"<<endl;
}
};
int main() {
MyEngine eng = MyEngine();
return 0;
}
The benefit here is, if tomorrow you create a new Box namely MyBox2 and want to create a custom engine MyEngine2 for that as well, simply inherit MyEngine : public Engine <MyBox2>. Just make sure to take care of type conversions.
As far as I remember, in Java you can declare Engine as something like Engine<extends T> which lets you instantiate Engine with any subtype of the template T provided. That is a safer and better way to do it, but I do not know if C++ provides something like that.
Hope it helps.
Consider using a wrapper for your ObjectManager.
NOTE marks the lines which will fail to compile if T and BaseT are not compatible.
Assuming:
template<class T>
ObjectManager{
T* objectAtIndex(size_t i); // As an example.
void insertAtIndex(T* object, size_t i); // As an example.
};
Wrapper:
template<class T, class BaseT>
class MyObjectManager
{
public:
ObjectManager<BaseT>* manager; // public for simplicity only!
T* objectAtIndex(size_t i){
return static_cast<T*>(manager->objectAtIndex(i)); // <- NOTE
}
void insertAtIndex(T* object, size_t i){
manager->insertAtIndex(object, i); // <- NOTE
}
};
Usage:
class MyEngine : public Engine
{
MyObjectManager<MyBox, Box> my_manager;
MyEngine(){
// Setup the manager(s).
manager = new ObjectManager<Box>();
my_manager.manager = manager;
// Example usage.
my_manager.insertAtIndex(new MyBox(), 0);
MyBox* p = my_manager.objectAtIndex(0);
}
};
This isn't possible without altering the Design in some way I think.
ObjectManager<Box> just isn't ObjectManager<MyBox> and it is not a base class of it but only the template arguments are base and derived of each other.
If your ObjectManager uses a pointer or smart pointer for the "managed" object...
template <class T>
class ObjectManager
{
T * object;
public:
ObjectManager(T * ptr) : object(ptr) { }
};
... you can construct the ObjectManager using a pointer to a derived object:
class MyEngine : public Engine
{
MyEngine()
{
manager = new ObjectManager<Box>(new MyBox);
}
};
If Engine is an abstract interface you could also have an own manager in MyEngine and use it to implement MyEngine
class MyEngine : public Engine
{
ObjectManager<MyBox> * mymanager;
MyEngine() : Engine(), mymanager(new ObjectManager<MyBox>)
{ }
};
You could provide an implementation to support the conversion. This should be similar to the way a std::unique_ptr can be implicitly converted from a derived pointer type to a base pointer type.
Example Code
#include <iostream>
#include <memory>
#include <vector>
class Box
{
public:
virtual ~Box() {}
virtual void foo() = 0;
};
class MyBox : public Box
{
public:
virtual ~MyBox() {}
virtual void foo() override
{
std::cout << "MyBox::foo()\n";
}
};
template<typename T>
class ObjectManager
{
public:
ObjectManager() {}
void add(T *object)
{
objects.emplace_back(object);
}
template<typename U>
ObjectManager<T> &operator=(ObjectManager<U> &other)
{
return *this;
}
std::size_t size() const
{
return objects.size();
}
T& operator[](std::size_t i)
{
return *objects[i];
}
private:
std::vector<std::unique_ptr<T>> objects;
};
class Engine
{
public:
ObjectManager<Box> manager;
};
class MyEngine : public Engine
{
public:
MyEngine()
{
manager = ObjectManager<MyBox>();
manager.add(new MyBox());
}
};
int main()
{
MyEngine engine;
for (std::size_t i = 0; i < engine.manager.size(); ++i)
{
engine.manager[i].foo();
}
return 0;
}
Example Output
MyBox::foo()
Another Example
This might help illustrate how to implement the conversion.
Example Code
template<typename T>
class MyPointer
{
public:
MyPointer() :
mPointer(nullptr)
{
// Do nothing
}
template<typename U>
MyPointer(MyPointer<U> &other) :
mPointer(other.mPointer)
{
other.mPointer = nullptr;
}
MyPointer(T *pointer) :
mPointer(pointer)
{
// Do nothing
}
template<typename U>
MyPointer<T> &operator=(MyPointer<U> &other)
{
mPointer = other.mPointer;
other.mPointer = nullptr;
return *this;
}
~MyPointer()
{
delete mPointer;
}
T* operator->()
{
return mPointer;
}
private:
template<typename U> friend class MyPointer;
T* mPointer;
};
int main()
{
{
MyPointer<MyBox> myBox(new MyBox());
MyPointer<Box> box;
box = myBox;
box->foo();
}
{
MyPointer<MyBox> myBox(new MyBox());
MyPointer<Box> box(myBox);
box->foo();
}
return 0;
}
Example Output
MyBox::foo()
MyBox::foo()
I'm trying to figure out a way to dynamically cast an instance of a child class to its parent in a somewhat difficult set of conditions.
Specifically, I have a an object hierarchy that looks something like (I've simplified a lot, so if something doesn't make sense, it might be due to the simplification):
class Object {
public:
virtual ~Object() {}
};
// shown just to give an idea of how Object is used
class IntObject: public Object {
protected:
int value;
public:
IntObject(int v) { value = v; }
int getValue() { return value; }
};
template <class T>
class ObjectProxy: public Object {
protected:
T *instance;
public:
ObjectProxy(T *instance): instance(instance) {}
T *getInstance() { return instance; }
};
The ObjectProxy class essentially acts as a wrapper to allow other types to be used in the Object hierarchy. Specifically, it allows pointers to class instances to be kept, and used later when invoking the instance's methods. For example, suppose I have:
class Parent {
protected:
int a;
public:
Parent(int v) { a = v; }
virtual ~Parent() {}
void setA(int v) { a = v; }
int getA() { return a; }
};
class Child: public Parent {
protected:
int b;
public:
Child(int v1, int v2): Parent(v1) { b = v2; }
void setA(int v) { b = v; }
int getB() { return b; }
};
I might use them in the following situation:
template <typename C>
void callFn(std::list<Object *> &stack, std::function<void (C*)> fn) {
Object *value = stack.front();
stack.pop_front();
ObjectProxy<C> *proxy = dynamic_cast<ObjectProxy<C> *>(value);
if (proxy == nullptr) {
throw std::runtime_error("dynamic cast failed");
}
fn(proxy->getInstance());
}
void doSomething(Parent *parent) {
std::cout << "got: " << parent->getA() << std::endl;
}
int main() {
std::list<Object *> stack;
// this works
stack.push_back(new ObjectProxy<Child>(new Child(1, 2)));
callFn<Child>(stack, doSomething);
// this will fail (can't dynamically cast ObjectProxy<Child> to ObjectProxy<Parent>)
stack.push_back(new ObjectProxy<Child>(new Child(1, 2)));
callFn<Parent>(stack, doSomething);
}
As noted in the above comments, this code fails for a known reason. In the sample code, it's easy to avoid invoking callFn<Parent>(stack, doSomething). However, in my real code, I am using the signature of the function to determine type, and if its a method for the parent class, that will automatically be used for the template parameter.
My question is if there is any way to achieve the dynamic cast from ObjectProxy from an object of type of ObjectProxy. Part of the complication comes from the fact that in the function callFn, you only have the Parent type and not the child type.
I looked into using type-erasure via boost::any (i.e. ObjectProxy stops being templated, and instead has boost::any instance), but still ran into problems when it came to dynamic-casting (boost::any_cast is static). I did find mention to a dynamic_any on SO, but have not gotten it to work properly yet.
Any help or insight into the problem is greatly appreciated.
The dynamic cast is failing because the classes that are instantiations of ObjectProxy do not share the same hierarchy as the types given in the parameterisation of ObjectProxy. I see two approaches that may help. One, you make the types given to ObjectProxy share a single common base class and move the dynamic cast away from ObjectProxy and onto the instances.
namespace approach2 {
struct object_t {
virtual ~object_t() { }
};
struct required_base_t {
virtual ~required_base_t() { }
};
class object_proxy_base_t : public object_t {
required_base_t* instance_;
public:
object_proxy_base_t(required_base_t* i) : instance_ (i) { }
template <class T>
T* cast_to() const
{
return dynamic_cast<T*>(instance_);
}
};
template <class value_t>
class object_proxy_t : public object_proxy_base_t {
value_t* instance_;
public:
object_proxy_t(value_t* i)
: object_proxy_base_t (i),
instance_ (i)
{
}
};
template <class value_t>
object_t* new_with_proxy(value_t const& value)
{
return new object_proxy_t<value_t>(new value_t(value));
}
struct parent_t : required_base_t {
virtual ~parent_t() { }
};
struct child_t : parent_t {
virtual ~child_t() { }
};
void f()
{
object_t* a = new_with_proxy(parent_t());
object_t* b = new_with_proxy(child_t());
std::cout
<< dynamic_cast<object_proxy_base_t*>(a)->cast_to<parent_t>() << '\n' // works
<< dynamic_cast<object_proxy_base_t*>(b)->cast_to<parent_t>() << '\n' // works
;
}
}
This approach is not possible if you cannot change the base classes of all types used by ObjectProxy. Which leads to the second solution where you make ObjectProxy instantiations have the same hierarchy as the types used to parameterise it.
namespace approach3 {
struct object_t {
virtual ~object_t() { }
};
struct empty_t {
template <class T>
empty_t(T*) { }
};
template <class value_t>
class object_proxy_t : public virtual object_t {
value_t* instance_;
public:
object_proxy_t(value_t* i) : instance_ (i) { }
};
template <class value_t, class base_t>
class object_proxy_sub_t :
public object_proxy_t<value_t>,
public base_t {
public:
object_proxy_sub_t(value_t* i)
: object_proxy_t<value_t>(i),
base_t (i)
{
}
};
template <class base_t, class value_t>
object_t* new_with_proxy(value_t const& value)
{
return new object_proxy_sub_t<value_t, base_t>(new value_t(value));
}
struct parent_t {
virtual ~parent_t() { }
};
struct child_t : parent_t {
virtual ~child_t() { }
};
void f()
{
object_t* a = new_with_proxy<empty_t>(parent_t());
object_t* b = new_with_proxy<object_proxy_t<parent_t> >(child_t());
std::cout
<< dynamic_cast<object_proxy_t<parent_t>*>(a) << '\n' // works
<< dynamic_cast<object_proxy_t<parent_t>*>(b) << '\n' // works
;
}
}
This approach places fewer requirements on the types involved but means more work to keep the hierarchies in sync.
Building off of Bowie Owen's first answer, I realized that while the types given would likely not be derived from the same class (it's a library), I could force that to occur:
struct ObjectProxyBaseType {
virtual ~ObjectProxyBaseType() {}
};
template <class T>
class ObjectProxyType: public ObjectProxyBaseType, public T {
public:
// allow construction via parameters
template <typename... Args>
ObjectProxyType(Args &&... args): T(std::move(args)...) {}
// or construction via copy constructor
ObjectProxyType(T *t): T(*t) {}
virtual ~ObjectProxyType() {}
};
Thus, if I have class Child, I can create an instance of ObjectProxyType<Child>, which causes it to also inherit ObjectProxyBaseType. The rest of the code follows Bowie's suggestion:
class ObjectProxy: public Object {
protected:
ObjectProxyBaseType *instance;
public:
template <typename T>
ObjectProxy(ObjectProxyType<T> *i) {
instance = i;
}
template <typename T>
ObjectProxy(T *value) {
instance = new ObjectProxyType<T>(value);
}
template <typename T>
T *castTo() const {
return dynamic_cast<T *>(instance);
}
};
And an example of code that works:
int main() {
std::list<Object *> stack;
stack.push_back(new ObjectProxy(new Child(1, 2)));
callFn<Child>(stack, doSomething);
stack.push_back(new ObjectProxy(new Child(5, 6)));
callFn<Parent>(stack, doSomething);
}
I've had to do something somewhat similar recently. I've used an approach which worked for me, but might not be appropriate in this case; use your discretion. This hinges on the fact that you (or the person extending this code, if any) have full knowledge of what hierarchies will be used as template parameters.
So let's say these hierarchies are the following:
class Parent1
class Child1: public Parent1
class Child11: public Child1
...
class Parent2
class Child2: public Parent2
...
Then you build a holder class. It is a bit complicated for a simple reason - my compiler doesn't support default template parameters on functions, so I am using helper structs to enable SFINAE.
This class needs to be able to hold objects belonging to all hierarchies (through a base class pointer).
class TypeHolder
{
template<class T, class E=void>
struct GetHelper
{
static T* Get(const TypeHolder* th) { return nullptr; }
//you can actually add code here to deal with non-polymorphic types through this class as well, if desirable
};
template<class T>
struct GetHelper<T, typename std::enable_if<std::is_polymorphic<T>::value, void>::type>
{
static T* Get(const TypeHolder* th)
{
switch(th->type)
{
case P1: return dynamic_cast<T*>(th->data.p1);
case P2: return dynamic_cast<T*>(th->data.p2);
//and so on...
default: return nullptr;
}
}
};
template<class T, class E=void>
struct SetHelper
{
static void Set(T*, TypeHolder* th) { th->type = EMPTY; }
};
template<class T>
struct SetHelper<T, typename std::enable_if<std::is_polymorphic<T>::value, void>::type>
{
static void Set(T* t, TypeHolder* th)
{
th->data.p1 = dynamic_cast<Parent1*>(t);
if(th->data.p1) { th->type = P1; return; }
th->data.p2 = dynamic_cast<Parent2*>(t);
if(th->data.p2) { th->type = P2; return; }
//...and so on
th->type = EMPTY;
}
};
public:
TypeHolder(): type(EMPTY) { }
template<class T>
T* GetInstance() const
{
return GetHelper<T>::Get(this);
}
template<class T>
void SetInstance(T* t)
{
SetHelper<T>::Set(t, this);
}
private:
union
{
Parent1* p1;
Parent2* p2;
//...and so on
} data;
enum
{
EMPTY,
P1,
P2
//...and so on
} type;
};
By the way, the reason we need the SFINAE trick is because of the dynamic_casts, which will not compile on non-polymorphic types.
Now all you need to do is modify your classes just a little bit :)
class ObjectProxyBase
{
public:
virtual const TypeHolder& GetTypeHolder() const = 0;
};
template<class T>
class ObjectProxy: public Object, public ObjectProxyBase
{
T* instance;
static TypeHolder th; //or you can store this somewhere else, or make it a normal (but probably mutable) member
public:
ObjectProxy(T* t): instance(t) { }
T* getInstance() const { return instance; }
const TypeHolder& GetTypeHolder() const { th.SetInstance(instance); return th; }
//... and the rest of the class
};
template<class T>
TypeHolder ObjectProxy<T>::th;
I hope this code is actually correct, since I mostly typed it into the browser window (mine used different names).
And now for the final piece: the function.
template <typename C>
void callFn(std::list<Object *> &stack, std::function<void (C*)> fn) {
Object *value = stack.front();
stack.pop_front();
ObjectProxyBase *proxy = dynamic_cast<ObjectProxyBase *>(value);
if (proxy == nullptr) {
throw std::runtime_error("dynamic cast failed");
}
C* heldobj = proxy->GetTypeHolder().GetInstance<C>(); //I used to have a dynamic_cast here but it was unnecessary
if (heldobj == nullptr) {
throw std::runtime_error("object type mismatch");
}
fn(heldobj);
}
You only need to use this approach for hierarchies, and can still use the dynamic_cast directly to ObjectProxy<C>* in other cases (essentially, you'll want to try both and see if one succeeds).
I hope this is at least a little bit helpful.
I suspect I can't do this directly using a PIMPL pattern. Is it possible to have a smart pointer to a template class? I have not been able to compile by turning knobs on the shared_ptr declaration.
// ============Foo.h ============
// Forward declare the implementation
template <typename T> class FooImpl;
class Foo
{
public:
Foo getInstance(const string& fooType);
...
private:
shared_ptr< FooImpl<T> > m_impl;
};
// ============FooImpl.h ============
template <typename T>
class FooImpl
{
...
};
Under Visual Studio 2008: "error C2065: 'T' : undeclared identifier". I receive a similar error under GCC. If I un-parameterize FooImpl (so that FooTempl inherits from FooImpl), the code will compile.
I suspect I can't paramaterize the smart pointer, but I could be wrong.
EDIT: The second Visual Studio error is more telling: "error C3203: 'FooImpl' : unspecialized class template can't be used as a template argument for template parameter 'T', expected a real type"
Jeff
I'm not entirely certain what you are trying to accomplish, but does this help?
Try 1:
// ============Foo.h ============
// Forward declare the implementation
template <typename T> class FooImpl;
template<class C>
class Foo
{
public:
Foo getInstance(const string& fooType);
...
private:
shared_ptr< FooImpl<C> > m_impl;
};
// ============FooImpl.h ============
template <typename T>
class FooImpl
{
...
};
Try 2:
// ============Foo.h ============
// Forward declare the implementation
class FooImplBase;
class Foo
{
public:
Foo getInstance(const string& fooType);
...
private:
shared_ptr< FooImplBase > m_impl;
};
// ============FooImpl.h ============
class FooImplBase {
public:
virtual void AnAPI();
virtual int AnotherAPI();
};
template <typename T>
class FooImpl : public FooImplBase
{
...
};
The code you have posted cannot compile since T does not mean anything in the context of Foo. The compiler expects a type called T here which does not exist there... Not entirely sure what you are trying to accomplish, but wouldn't the following solve your problem?
// ============Foo.h ============
class FooImplBase {
virtual void WhateverFooImplIsSupposedToDo() = 0;
};
template <typename T> class FooImpl : public FooImplBase {
T mInstance;
public:
FooImpl(T const & pInstance) : mInstance(pInstance) {}
virtual void WhateverFooImplIsSupposedToDo()
{
// implementation which deals with instances of T
}
};
class Foo
{
public:
Foo getInstance(const string& fooType) {
// use m_impl->WhateverFooImplIsSupposedToDo...
}
template < class T >
Foo( T const & pInstance ) : m_impl(new FooImpl<T>(pInstance)) {}
private:
shared_ptr< FooImplBase > m_impl;
};
You're doing it right, just make sure T is defined. This compiles for me on MSVC++ 2010:
#include <memory>
using namespace std;
template<class T>
class Blah {
public:
Blah() { }
};
class Foo {
public:
shared_ptr<Blah<int>> ptr;
Foo() : ptr(new Blah<int>()) { }
};
If you're on an older compiler that hasn't incorporated this feature of C++11 yet, change
shared_ptr<Blah<int>> ptr;
To
shared_ptr<Blah<int> > ptr;
So the compiler doesn't think the >> is a right shift. C++11 doesn't have this problem though.
I don't know in advance I am going to have a Blah, only a Blah.
From the language point of view, Blah<T> is meaningless because T doesn't exist. Depending on what you're exactly trying to do, you can
make Foo a template, too, so that you can declare a template parameter T:
template<typename T>
class Foo
{
public:
Foo getInstance(const string& fooType);
...
private:
shared_ptr< FooImpl<T> > m_impl;
};
which 'fixes' the choice of T when you declare a variable of type Foo<T>;
or make FooImpl explicitly derive from a common base:
class FooBase {
// need to define the interface here
};
// this is a class definition whereas previously you only needed a declaration
template<typename T>
class FooImpl: public FooBase {
// definition here
};
class Foo
{
public:
Foo getInstance(const string& fooType);
// we needed the definition of FooImpl for this member
// in addition this member is quite obviously a template
template<typename T>
void
set(FooImpl<T> const& foo)
{
m_impl.reset(new FooImpl<T>(foo));
}
// not a member template!
void
use()
{
// any use of m_impl will be through the FooBase interface
}
private:
shared_ptr<FooBase> m_impl;
};
where for a given Foo instance any kind of FooImpl<T> can be set dynamically and then used through the FooBase interface. This is a kind of type erasure as it's called in the C++ world.
We can use templates to write a generic smart pointer class. Following C++ code demonstrates the same. We don't need to call delete 'ptr', when the object 'ptr' goes out of scope, destructor for it is automatically.
#include<iostream>
using namespace std;
// A generic smart pointer class
template <class T>
class SmartPtr
{
T *ptr; // Actual pointer
public:
// Constructor
explicit SmartPtr(T *p = NULL) { ptr = p; }
// Destructor
~SmartPtr() {
cout <<"Destructor called" << endl;
delete(ptr);
}
// Overloading dereferncing operator
T & operator * () { return *ptr; }
// Overloding arrow operator so that members of T can be accessed
// like a pointer (useful if T represents a class or struct or
// union type)
T * operator -> () { return ptr; }
};
int main()
{
SmartPtr<int> ptr(new int()); // Here we can create any data type pointer just like 'int'
*ptr = 20;
cout << *ptr;
return 0;
}
out put:
20
Destructor called
I have a base class and a few derivative. I have to 'register' some static function from each of them. Here is the example:
class Base
{
// Some interface...
};
class Der1 : Base
{
static void Do();
};
class Der2 : Base
{
static void Do();
};
void processStatic()
{
SomeFunc(Der1::Do);
SomeFunc(Der2::Do);
}
As you see, SomeFunc receives function pointer. I want to do that automatically with each new derivative class, is it possible? Maybe, predefine static function in Base class and register it there. But I think it's impossible, yes?
Maybe, this will be more easier to understand what do I want:
class Der1 : Base
{
Der1() { SomeFunc(Der1::Do); }
static void Do();
};
class Der2 : Base
{
Der2() { SomeFunc(Der2::Do); }
static void Do();
};
EDIT: Completely replacing previous answer due to clarified requirements.
You could use the CRTP to declare a specialized base class that does nothing more than call your registration function:
#include <iostream>
void SomeFunc(void(*fp)()) {
(*fp)();
};
template <class D>
struct ExtraBass {
ExtraBass() {
static bool once;
if(!once)
SomeFunc(D::Do);
once = true;
}
};
struct Bass {
};
struct Drive : Bass, ExtraBass<Drive> {
static void Do() { std::cout << "Drive::Do\n"; }
};
struct Deride : Bass , ExtraBass<Deride> {
static void Do() { std::cout << "Deride::Do\n"; }
};
int main() {
Drive d1;
Deride d2;
Deride d3;
}
This is not an easy thing to do in C++, but I'm not saying it's impossible. If all you need is a list of subclass names, these answers might help:
Somehow register my classes in a list
c++ List of classes without initializing them for use of static functions
Seems either macro magic or boost mpl is your tool of choice.
I just wondering, if you did something like
void SomeFunc(void (*doFunc)())
{
doFunc();
}
template <class T> int Register()
{
SomeFunc(T::Do);
return 0;
}
template <class T> class Base
{
static int _i;
};
template <class T> int Base<T>::_i = Register<T>();
class Derived : Base<Derived>
{
public:
static void Do() { }
};
template <typename T>
class BaseQueue
{
public :
virtual void push_back(T value) = 0;
//other virtual methods
};
template <typename T>
class BaseDeque: public virtual BaseQueue<T>
{
public:
virtual void push_front(T value) = 0;
//other virtual methods
};
//Realisation
template <typename T>
class VectorQueue: public BaseQueue<T>
{
typedef typename std::vector<T> array;
private: array adata;
public:
VectorQueue()
{
adata = array();
}
void push_back(T value)
{
adata.push_back(value);
}
};
template <typename T>
class VectorDeque: virtual public VectorQueue<T>, virtual protected BaseDeque<T>//,
{
void push_front(T value)
{
VectorQueue::adata.push_front(value);
}
};
int _tmain(int argc, _TCHAR* argv[])
{
VectorDeque<int> vd = VectorDeque<int>();//here is a error
int i;
std::cin >> i;
return 0;
}
I have such error: "C2259: 'VectorDeque' : cannot instantiate abstract class ...". How can I fix it? Class VectorQueue has realize every virtual method of BaseQueue class already. But the compiler doesn't know it. The only way I see is to write something like this:
template <typename T>
class VectorDeque: virtual public VectorQueue<T>, virtual protected BaseDeque<T>//,
{
void push_front(T value)
{
VectorQueue::adata.push_front(value);
}
void push_back(T value)
{
VectorQueue::push_back(value);
}
//repeat it fo every virtual method of BaseQueue class (interface)
};
But it's awful.
push_back from BaseQueue isn't implemented on the BaseDeque side of the inheritance chain, and thus the childmost class is still abstract.
I think you're trying to force a class relationship here that shouldn't exist. Note how in the standard library deque and vector are distinct container types and things like queue adapt those containers to very precise interfaces rather than trying to inherit.
Even if you solve your diamond issue (or follow #Mark B's advice and keep them separate), you have a few other issues in there:
template <typename T>
class VectorQueue: public BaseQueue<T>
{
typedef typename std::vector<T> array;
private: array adata; // if this is private, VectorDeque can't reach it
public:
// constructors have an initializer section
// member variables should be initialized there, not in the body
VectorQueue()
// : adata() // however, no need to explicitly call default constructor
{
// adata = array();
}
};
template <typename T>
class VectorDeque: virtual public VectorQueue<T>, virtual protected BaseDeque<T>
{
void push_front(T value)
{
// if adata is protected, you can just access it. No need for scoping
/*VectorQueue::*/ adata.push_front(value);
// Error: std::vector doesn't have a method push_front.
// Perhaps you meant to use std::list?
}
};
Multiple inheritance and static polymorphism are of help, for instance:
// Abstract bases
template <typename T, typename Val>
class BaseQueue
{
public :
void push_back(Val val)
{
static_cast<T*>(this)->push_back(val);
}
// ...
};
template <typename T, typename Val>
class BaseDeque
{
public:
void push_front(Val val)
{
static_cast<T*>(this)->push_front(val);
}
// ...
};
// Concrete class
#include <deque>
template <typename Val>
class QueueDeque:
public BaseQueue<QueueDeque<Val>, Val>,
public BaseDeque<QueueDeque<Val>, Val>
{
std::deque<Val> vals;
public:
void push_front(Val val)
{
vals.push_front(val);
}
void push_back(Val val)
{
vals.push_back(val);
}
// etc..
};
int main()
{
QueueDeque<int> vd;// no more error
vd.push_front(5);
vd.push_back(0);
return 0;
}