• Advertisement

Archived

This topic is now archived and is closed to further replies.

Weird inheritence + template problem

This topic is 4971 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Sorry for all the posts recently, but I''ve started going into the "uncharted waters" of my programming experience, and now that I''m running into difficulties, I have no idea what''s going on. Now, I have a base MemObj (object with a reference count) and MemPtr (a smart pointer that takes MemObj''s as a class template) defined as the following:
#ifndef _ERIK_MEMOBJ_H_DEFINED
#define _ERIK_MEMOBJ_H_DEFINED

#include <assert.h>
#include <list>

/////////////////////////////////////////////////////////////////////////////

//	MEMOBJ.H

/////////////////////////////////////////////////////////////////////////////

//

// AUTHOR: ERIK GOLDMAN

// DATE:  6-3-04

// DESC: The base memory-managed object class

// NOTES:

// TOFIX:

/////////////////////////////////////////////////////////////////////////////

class MemObj
{
protected:
	int m_refs;

public:
	static std::list<MemObj*> m_deadObjects;

	MemObj()
	:m_refs(0)
	{
	}

	virtual ~MemObj()
	{
	}

	void attach()
	{
		++m_refs;
	}
	void release()
	{
		--m_refs;
		if(m_refs==0)		// nothing points to the object

		{
			//MemoryManager::getInstance()->markForDeletion(this);

			m_deadObjects.push_back(this);		// mark for deletion

		}
	}
};

/////////////////////////////////////////////////////////////////////////////

//	MEMPTR

/////////////////////////////////////////////////////////////////////////////

//

// AUTHOR: ERIK GOLDMAN

// DATE:  6-3-04

// DESC: A smart pointer to a memory-managed object

// NOTES:

// TOFIX:

/////////////////////////////////////////////////////////////////////////////


template <class T>
class MemPtr
{
protected:
	T *obj;

public:
	MemPtr()
	:obj(0)
	{
	}

	MemPtr(const MemPtr<T> &p)
	:obj(p.obj)
	{
		if(obj)
			obj->attach();
	}

	MemPtr(T *p)
	:obj(p)
	{
		if(obj)
			obj->attach();
	}

	~MemPtr()
	{
		if(obj)
			obj->release();
		obj=0;
	}

	inline MemPtr &operator=(T *p)
	{
		if(p != obj)		// prevent against self-assignment

		{
			if(obj)
				obj->release();
			obj=p;
			if(obj)
				obj->attach();
		}
		return *this;
	}

	inline MemPtr &operator=(const MemPtr &p)
	{
		if(p.obj != obj)	// prevent against self-assignment

		{
			if(obj)
				obj->release();
			obj=p.obj;
			if(obj)
				obj->attach();
		}
		return *this;
	}

	inline T& operator*() const
	{
		assert(obj!=0);
		return *obj;
	}

	inline T *operator->() const
	{
		assert(obj!=0);
		return obj;
	}

	inline bool operator==(const MemPtr<T> &p)
	{
		return(p.obj == obj);
	}

	inline bool operator ==(const T *p)
	{
		return(obj == p);
	}

	inline bool operator !()
	{
		return (obj == 0);
	}

	inline bool isValid()
	{
		return (obj != 0);
	}
};

#endif
And then I have the BaseDator and Dator class, straight from Enginuity:
#ifndef _ERIK_DATOR_H_DEFINED
#define _ERIK_DATOR_H_DEFINED

#include "MemObj.h"
#include <string>

/////////////////////////////////////////////////////////////////////////////

//	DATOR.H

/////////////////////////////////////////////////////////////////////////////

//

// AUTHOR: ERIK GOLDMAN

// DATE:  6-3-04

// DESC: The Dator function encapsulates data members

// NOTES: Thanks to the Enginuity tutorial for this: www.gamedev.net

// TOFIX:

/////////////////////////////////////////////////////////////////////////////


class BaseDator : public MemObj
{
protected:
  BaseDator(){}
  BaseDator(BaseDator &b){(*this)=b;}
public:
  virtual BaseDator &operator =(std::string &s)=0;
  virtual BaseDator &operator +=(std::string &s)=0;
  virtual BaseDator &operator -=(std::string &s)=0;
  virtual bool operator ==(std::string &s)=0;
  virtual bool operator !=(std::string &s)=0;

  virtual bool hasMultipleValues()=0;

  virtual operator std::string()=0;
};

/////////////////////////////////////////////////////////////////////////////

//	DATOR

/////////////////////////////////////////////////////////////////////////////

//

// AUTHOR: ERIK GOLDMAN

// DATE:  6-3-04

// DESC: A one-variable data type that is encapsulated in a dator

// NOTES:

// TOFIX:

/////////////////////////////////////////////////////////////////////////////

template<class T>
class Dator : public BaseDator
{
protected:
  T& target;

  T toVal(std::string &s)
  {
    std::stringstream str;
    str.unsetf(std::ios::skipws);
    str<<input;
    T res;
    str>>res;
    return res;
  }

  std::string toString(T &val)
  {
    std::stringstream str;
    str.unsetf(std::ios::skipws);
    str<<val;
    std::string res;
    str>>res;
    return res;
  }

public:
  Dator(T& t) : target(t) {}
  BaseDator &operator =(std::string &input)
    { target=toVal(input); return *this; }
  BaseDator &operator +=(std::string &input)
    { target+=toVal(input); return *this; }
  BaseDator &operator -=(std::string &input)
    { target-=toVal(input); return *this; }
  bool operator ==(std::string &s) { return (s==(std::string)(*this)); }
  bool operator !=(std::string &s) { return (s!=(std::string)(*this)); }
  operator std::string() { return toString(target); }

  bool hasMultipleValues() { return false; }
};

/////////////////////////////////////////////////////////////////////////////

//	LISTDATOR

/////////////////////////////////////////////////////////////////////////////

//

// AUTHOR: ERIK GOLDMAN

// DATE:  6-3-04

// DESC: A list of values encapsulated in a Dator

// NOTES:

// TOFIX:

/////////////////////////////////////////////////////////////////////////////

template<class T>
class ListDator : public BaseDator
{
protected:
  std::list<T> &values;
  T toVal(std::string &s)
  {
    std::stringstream str;
    str.unsetf(std::ios::skipws);
    str<<input;
    T res;
    str>>res;
    return res;
  }
  std::string toString(T &val)
  {
    std::stringstream str;
    str.unsetf(std::ios::skipws);
    str<<val;
    std::string res;
    str>>res;
    return res;
  }
public:
  ListDator(std::list<T> &v) : values(v) { }
  BaseDator &operator =(std::string &s)
    { values.clear(); values.push_back(toVal(s)); return *this; }
  BaseDator &operator +=(std::string &s)
    { values.push_back(toVal(s)); return *this; }
  BaseDator &operator -=(std::string &s)
    { values.remove(toVal(s)); return *this; }
  bool operator ==(std::string &s)
    { return (std::find(values.begin(),values.end(),toVal(s))!=values.end()); }
  bool operator !=(std::string &s) { return !((*this)==s); }
  
  operator std::string() { return toString(values.back()); }
  operator std::list<T>&() { return values; }

  bool hasMultipleValues(){return true;}
};

#endif
Here''s where the dilemma is, however: I have a function that takes a MemPtr<baseDator> and I try to pass a MemPtr to it... and it gives me an error!
C:\Strnad Project\KutatasEngine\KutatasMain.cpp(220) : error C2664: ''RegisterSetting'' : cannot convert parameter 2 from ''class MemPtr<class Dator<float> >'' to ''class MemPtr<class BaseDator>''
        No constructor could take the source type, or constructor overload resolution was ambiguous
Now, what is going on? Here is the problematic function:
//////////////////////////////////////////////////////////////////////////////////////////

// Name: RegisterSetting

// Desc: Adds a setting to the setting map

// Notes:

// ToFix:

//////////////////////////////////////////////////////////////////////////////////////////

void SettingsManager::RegisterSetting(std::string &name, MemPtr<BaseDator> v)
{
	m_settingsMap[name]=v;
}
and I pass it:
float e=6.9;
	MemPtr<Dator<float> > test= new Dator<float>(e);
	SettingsManager *s=SettingsManager::getInstance();
	s->RegisterSetting(std::string("Dizzle"), test);
Thanks!

Share this post


Link to post
Share on other sites
Advertisement
Well, you never did tell it how to convert from ''class MemPtr<class Dator<float> >'' to ''class MemPtr<class BaseDator>''...

Give the MemPtr class a templated constructor that can take any MemPtr and see how you go from there.

Share this post


Link to post
Share on other sites
Remove the existing copy constructor and use a templated one:

template <class U>
MemPtr(const MemPtr<U> &p)
:obj(p.get())
{
if (obj)
obj->attach();
}

T* get() const { return obj; } // A MemPtr<T> doesn''t have direct access to MemPtr<U>::obj, so a getter is necessary.

Share this post


Link to post
Share on other sites
Nope, nothing.


/////////////////////////////////////////////////////////////////////////////

// MEMPTR

/////////////////////////////////////////////////////////////////////////////

//

// AUTHOR: ERIK GOLDMAN

// DATE: 6-3-04

// DESC: A smart pointer to a memory-managed object

// NOTES:

// TOFIX:

/////////////////////////////////////////////////////////////////////////////


template <class T>
class MemPtr
{
protected:
T *obj;

public:
MemPtr()
:obj(0)
{
}

/*
MemPtr(const MemPtr<T> &p)
:obj(p.obj)
{
if(obj)
obj->attach();
}
*/


template <class U>
MemPtr(const MemPtr<U> &p)
:obj(p.getObj())
{
if (obj)
obj->attach();
}

MemPtr(T *p)
:obj(p)
{
if(obj)
obj->attach();
}

~MemPtr()
{
if(obj)
obj->release();
obj=0;
}

inline MemPtr &operator=(T *p)
{
if(p != obj) // prevent against self-assignment

{
if(obj)
obj->release();
obj=p;
if(obj)
obj->attach();
}
return *this;
}

inline MemPtr &operator=(const MemPtr &p)
{
if(p.obj != obj) // prevent against self-assignment

{
if(obj)
obj->release();
obj=p.obj;
if(obj)
obj->attach();
}
return *this;
}

inline T& operator*() const
{
assert(obj!=0);
return *obj;
}

inline T *operator->() const
{
assert(obj!=0);
return obj;
}

inline T *getObj()
{
return obj;
}

inline bool operator==(const MemPtr<T> &p)
{
return(p.obj == obj);
}

inline bool operator ==(const T *p)
{
return(obj == p);
}

inline bool operator !()
{
return (obj == 0);
}

inline bool isValid()
{
return (obj != 0);
}
};


So then:

MemPtr<ClassFunctor<RenderManager> > forward=new ClassFunctor<RenderManager>(RenderManager::getInstance(), RenderManager::incZpos);
keymap->Assign(DIK_W, forward);


Results in


C:\Strnad Project\KutatasEngine\KutatasMain.cpp(168) : error C2664: ''Assign'' : cannot convert parameter 2 from ''class MemPtr<class ClassFunctor<class RenderManager> >'' to ''class MemPtr<class Functor> &''
A reference that is not to ''const'' cannot be bound to a non-lvalue


When it''s the same situation...

#ifndef _ERIK_FUNCTOR_H_DEFINED
#define _ERIK_FUNCTOR_H_DEFINED

/////////////////////////////////////////////////////////////////////////////

// FUNCTOR.H

/////////////////////////////////////////////////////////////////////////////

//

// AUTHOR: ERIK GOLDMAN

// DATE: 6-3-04

// DESC: Encapsulated function pointers- standard and for member pointers

// NOTES: I haven''t tried these yet

// TOFIX:

/////////////////////////////////////////////////////////////////////////////


#include "MemObj.h"

class Functor:public MemObj
{
protected:
void (*fp)(); // void function pointer

public:
virtual void operator()()
{
(*fp)();
}

Functor(void (*f)())
:fp(f)
{
}

Functor(const Functor &f)
:fp(f.fp)
{
}
};

/////////////////////////////////////////////////////////////////////////////

// CLASSFUNCTOR

/////////////////////////////////////////////////////////////////////////////

//

// AUTHOR: ERIK GOLDMAN

// DATE: 6-3-04

// DESC: A functor that allows usage of a member variable

// NOTES:

// TOFIX:

/////////////////////////////////////////////////////////////////////////////


template<class tClass> class ClassFunctor:public Functor
{
private:
void (tClass::*fPtr)(); // pointer to member function

tClass* objPtr; // pointer to object


public:

// constructor - takes pointer to an object and pointer to a member and stores

// them in two private variables

ClassFunctor(tClass* _pt2Object, void(tClass::*_fpt)())
:objPtr(_pt2Object), fPtr(_fpt)
{
}

ClassFunctor(const ClassFunctor &c)
:objPtr(c.objPtr), fPtr(c.fPtr)
{
}

// override operator "()"

virtual void operator()()
{
(*objPtr.*fPtr)();
}

virtual void set(tClass *c, void(tClass::*fp)())
{
objPtr=c;
fPtr=fp;
}
};

/////////////////////////////////////////////////////////////////////////////

// MEMCLASSFUNCTOR

/////////////////////////////////////////////////////////////////////////////

//

// AUTHOR: ERIK GOLDMAN

// DATE: 6-3-04

// DESC: A memory-managed version of the ClassFunctor- this counts as a

// reference to a MemObj

// NOTES:

// TOFIX:

/////////////////////////////////////////////////////////////////////////////


template<class t> class MemClassFunctor:public ClassFunctor<t>
{
private:
void (t::*fPtr)(); // pointer to member function

MemPtr<t> objPtr; // pointer to object


public:

// constructor - takes pointer to an object and pointer to a member and stores

// them in two private variables

MemClassFunctor(t* _pt2Object, void(t::*_fpt)())
:objPtr(_pt2Object), fPtr(_fpt)
{
}

MemClassFunctor(const MemClassFunctor &m)
:objPtr(m.objPtr), fPtr(m.fPtr)
{
}

// override operator "()"

virtual void operator()()
{
(*objPtr.*fPtr)();
}

void set(t *c, void(t::*fp)())
{
objPtr=c;
fPtr=fp;
}
};
#endif


And then

//////////////////////////////////////////////////////////////////////////////////////////

// Name: Assign

// Desc: Maps a key to a function

// Notes:

// ToFix:

//////////////////////////////////////////////////////////////////////////////////////////

void InputKeymap::Assign(int key, MemPtr<Functor> &f)
{
m_keymap[key]=f;
}



So I''m stumped now.

Share this post


Link to post
Share on other sites
Crapola, now we have even more problems.

Here are the errors I''m getting:

:\strnad project\kutatasengine\memobj.h(72) : error C2662: ''getObj'' : cannot convert ''this'' pointer from ''const class MemPtr<class ClassFunctor<class MemoryManager> >'' to ''class MemPtr<class ClassFunctor<class MemoryManager> > &''
Conversion loses qualifiers
C:\Strnad Project\KutatasEngine\KutatasMain.cpp(168) : see reference to function template instantiation ''__thiscall MemPtr<class Functor>::MemPtr<class Functor>(const class MemPtr<class ClassFunctor<class MemoryManager> > &)'' being compiled
c:\strnad project\kutatasengine\memobj.h(74) : fatal error C1903: unable to recover from previous error(s); stopping compilation
C:\Strnad Project\KutatasEngine\KutatasMain.cpp(168) : see reference to function template instantiation ''__thiscall MemPtr<class Functor>::MemPtr<class Functor>(const class MemPtr<class ClassFunctor<class MemoryManager> > &)'' being compiled


Here''s the MemObj/MemPtr again:

#ifndef _ERIK_MEMOBJ_H_DEFINED
#define _ERIK_MEMOBJ_H_DEFINED

#include <assert.h>
#include <list>

/////////////////////////////////////////////////////////////////////////////

// MEMOBJ.H

/////////////////////////////////////////////////////////////////////////////

//

// AUTHOR: ERIK GOLDMAN

// DATE: 6-3-04

// DESC: The base memory-managed object class

// NOTES:

// TOFIX:

/////////////////////////////////////////////////////////////////////////////

class MemObj
{
protected:
int m_refs;

public:
static std::list<MemObj*> m_deadObjects;

MemObj()
:m_refs(0)
{
}

virtual ~MemObj()
{
}

void attach()
{
++m_refs;
}
void release()
{
--m_refs;
if(m_refs==0) // nothing points to the object

{
m_deadObjects.push_back(this); // mark for deletion

}
}
};

/////////////////////////////////////////////////////////////////////////////

// MEMPTR

/////////////////////////////////////////////////////////////////////////////

//

// AUTHOR: ERIK GOLDMAN

// DATE: 6-3-04

// DESC: A smart pointer to a memory-managed object

// NOTES:

// TOFIX:

/////////////////////////////////////////////////////////////////////////////


template <class T>
class MemPtr
{
protected:
T *obj;

public:
MemPtr()
:obj(0)
{
}

template <class U>
MemPtr(const MemPtr<U> &p)
:obj(p.getObj())
{
if (obj)
obj->attach();
}

MemPtr(T *p)
:obj(p)
{
if(obj)
obj->attach();
}

~MemPtr()
{
if(obj)
obj->release();
obj=0;
}

inline MemPtr &operator=(T *p)
{
if(p != obj) // prevent against self-assignment

{
if(obj)
obj->release();
obj=p;
if(obj)
obj->attach();
}
return *this;
}

inline MemPtr &operator=(const MemPtr &p)
{
if(p.obj != obj) // prevent against self-assignment

{
if(obj)
obj->release();
obj=p.obj;
if(obj)
obj->attach();
}
return *this;
}

inline T& operator*() const
{
assert(obj!=0);
return *obj;
}

inline T *operator->() const
{
assert(obj!=0);
return obj;
}

inline T *getObj()
{
return obj;
}

inline bool operator==(const MemPtr<T> &p)
{
return(p.obj == obj);
}

inline bool operator ==(const T *p)
{
return(obj == p);
}

inline bool operator !()
{
return (obj == 0);
}

inline bool isValid()
{
return (obj != 0);
}
};

#endif


And then the code that''s causing the error:

MemoryManager *memManage=MemoryManager::getInstance();
RenderManager *renderer=RenderManager::getInstance();

MemPtr<InputKeymap> keymap=new InputKeymap();
MemPtr<Functor> escape=new Functor(&ExitProgram);
keymap->Assign(DIK_ESCAPE, escape);

MemPtr<ClassFunctor<MemoryManager> > testing=new ClassFunctor<MemoryManager>
(MemoryManager::getInstance(), MemoryManager::checkMemory);
keymap->Assign(DIK_A, testing);

Share this post


Link to post
Share on other sites
The error is saying that it can''t call getObj on a const object. getObj should logically be usable with a const object, so declare it as const:

inline T *getObj() const

For that matter, operator ==, operator !=, operator ! and isValid should also be const.

Share this post


Link to post
Share on other sites
Aha! Thank you for that... I know I''ve gotten that error in the past without knowing what it means!

Phew, I''ve really learned quite a bit in this thread! Thanks all!

Share this post


Link to post
Share on other sites

  • Advertisement