Hey all,

I got interested in using smart pointers and tried to implement the following solution: http://www.davethehat.com/articles/smartp.htm
It's probably far from perfect but this is mainly a learning experience.

It's a non intrusive reference counted implementation of a smart ptr. And somewhere in the article the assignment operator is defined:

template<class T>
ObjVar<T>& operator=(const ObjVar<T>& rVar)
{
        if (!rVar.Null())
                rVar.m_pCounted->GetRef();
        UnBind();
        m_pCounted = rVar.m_pCounted;
        return *this;
}

the m_pCounted object is a pointer to the following class:

template <class T> class Objvar;

template <class T>
class Counted
{
        friend class ObjVar<T>;
private:
        Counted(T* pT) : Count(0), my_pT(pT) 
                           { ASSERT(pT != 0); }
        ~Counted()         { ASSERT(Count == 0); delete my_pT; }

        unsigned GetRef()  { return ++Count; }
        unsigned FreeRef() { ASSERT(Count!=0); return --Count; }

        T* const my_pT;
        unsigned Count;
};

When you put the code in the article together everything seems to work fine but assignment of a derived class smart ptr to a base class smart ptr seems to fail:

ObjVar<CBaseClass> basePtr;
ObjVar<CDerivedClass> derivedPtr;

basePtr = derivedPtr;

It fails because the compiler complains about the following assignment in the assignment operator of the ObjVar class:

m_pCounted = rVar.m_pCounted;

In this case m_pCounted would be of type: Counted<CBaseClass> * and the rVar.m_pCounted is of type: Counted<CDerivedClass> *. How can I make this assignment work? It seems valid that the compiler is complaining because the template arguments are different but it somehow doesn't make sense to me since the types are closely related. After all, we are allowed to do something like:

CBaseClass *basePtr;
CDerivedClass *derivedPtr;

basePtr = derivedPtr;

Recommended Answers

All 7 Replies

template <class T> class Objvar;

C++ is case-sensitive. Try fixing your forward declaration.

template <class T> class Objvar;

C++ is case-sensitive. Try fixing your forward declaration.

Yes you are right, that code is actually a copy paste from the article i mentioned in my first post. I fixed that in my own code already, so it's not an issue anymore.

The actual error i'm getting is:

error C2440: '=' : cannot convert from 'Counted<T> * ' to 'Counted<T> *'
 with
        [
            T=CDerivedClass
        ]
        and
        [
            T=CBaseClass
        ]
        Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast

Use of a friend class is not inheritance. The Derived class (Counted) doesn't inherit from the Base class (seems to be ObjVar). In order for a pointer-to-base to hold a pointer-to-derived, there must be inheritance.

Check out this inheritance tutorial.

//basic inheritance
class baseClassName
{
private:
  /* non-accessible members */
protected:
  /* accessible inheritable members */
public:
  /* public members */
}

class derivedClassName : access-specifier baseClassName
{
private:

protected:

public:

}

Use of a friend class is not inheritance. The Derived class (Counted) doesn't inherit from the Base class (seems to be ObjVar). In order for a pointer-to-base to hold a pointer-to-derived, there must be inheritance.

Check out this inheritance tutorial.

//basic inheritance
class baseClassName
{
private:
  /* non-accessible members */
protected:
  /* accessible inheritable members */
public:
  /* public members */
}

class derivedClassName : access-specifier baseClassName
{
private:

protected:

public:

}

When I'm talking about base/derived class i meant the types I pass to the smart ptr. I have a base and derived class wrapped in the given smart ptr implementation. Assigning the derived class smart ptr to the base class smart ptr should work, but it doesn't.

Maybe this example makes it easier to understand what my problem really boils down to:

template <class T>
class A
{
	public:
		A(T *pT)
		{
			m_Ptr = pT;
		}

	private:
		T *m_Ptr;
};

class CBase
{
    /* details omitted */
};

class CDerived : public CBase
{
    /* details omitted */
};

int main(int argc, char *argv[])
{
    A<CBase> *basePtr
    A<CDerived> *derivedPtr;

    basePtr = derivedPtr;

    return 0;
}

How to make the basePtr = derivedPtr assignment work? In my understanding it should be possible to get it to work (using implicit casting?) since the template arguments are closely related.

What is m_pCounted and where is it defined? The only place I see it is in your overloaded assignment. I suspect it should actually be my_pT, but you have specified my_pT as a const pointer, not a pointer to a const object, which prevents you re-assigning it. If this was not your intent, I suggest you read this.

What is m_pCounted and where is it defined? The only place I see it is in your overloaded assignment. I suspect it should actually be my_pT, but you have specified my_pT as a const pointer, not a pointer to a const object, which prevents you re-assigning it. If this was not your intent, I suggest you read this.

Can you check out the brief example i posted in my previous reply? It generates the same error and doesn't use the const keyword. It reproduces what is actually happening in the more complex smart pointer class.

A<Base> and A<Derived> are not the same type, and they do not inherit from each other. I looked up an example. That example created two A<Base> then directly created a pointer a new object of the Derived type. That version also defined copy constructor(s) instead of assignment operators as well as custom allocators though. That example is found here.

I'm afraid I'll have to bow out of any further discussion here, it's getting beyond me.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.