Can I make an assignment operator on a base class

2019-08-14 03:05发布

问题:

Sorry for the bad title... I have a base class like:

template<class T>
class GPtr
{
public:
    typedef T BaseType;

    GPtr& operator=(const BaseType& rhs)
    {
        ...
    }
};

I often want to make subclassed specializations like:

class GraphicPtr : public GPtr<Graphic>
{
...
};

However my base-class assignment operator still returns GPtr<Graphic> not GraphicPtr and it's annoying to have to copy-paste code in case the core assignment operator functionality should change later.

Is there a neat way to define the base-class assignment operator so it returns the type of the actual class in use?

回答1:

In C++, the base class has no idea of it's children. You may add a template parameter that will be the derived class and use it.

template<class T, class Derived>
class GPtr
{
public:
    typedef T BaseType;

    Derived& operator=(const BaseType& rhs)
    {
        ...
    }
};


回答2:

Maybe you can use the CRTP instead?

#include <iostream>

template<class Derived>
class GPtr
{
public:
    typedef Derived DerivedType;

    GPtr& operator=(const GPtr& rhs)
    {
        std::cout << "GPtr::operator=" << std::endl;

        return *this;
    }
};

class GraphicDerived : public GPtr<GraphicDerived>
{
    public: 

        GraphicDerived& operator=(const GraphicDerived& rhs)
        {
            std::cout << "GraphicDerived::operator=" << std::endl;
            // Inheiriting shadows the name of the base operator= which 
            // needs to be explicitly called.
            GPtr<GraphicDerived>::operator=(rhs); 
            return *this;
        };
};

class Graphic {};

using namespace std;

int main()
{


    GraphicDerived one; 
    GraphicDerived two;

    cout << "derived assignment: " << endl;
    one = two;

    GPtr<Graphic> ptrOne;
    GPtr<Graphic> ptrTwo;

    cout << "GPtr assignment stnadalone : " << endl;

    ptrOne = ptrTwo; 
};

Results with:

derived assignment: 
GraphicDerived::operator=
GPtr::operator=
GPtr assignment stnadalone : 
GPtr::operator=


回答3:

What you are asking for does not really make sense. When the base object is being assigned, it cannot possibly know which of the potentially infinite number of derived types it is being called from, and thus cannot return a different type in each case. Furthermore, even if that was possible, it would not be possible to use that in real code.

C++ resolves everything but polymorphic calls at runtime, and even for polymorphic calls it only delays finding the exact override, but not the signature (i.e. even with covariant return types, the return type of the base override will be used.

Technically it can be done, with or without templates, but all of them exhibit the same core issue: The base class can only be a base class for a single type, the type returned by the assignment operator, limiting the usability as a base class.

What is the real problem that you want to solve?

The approach that you are taking does not seem appropriate. It would be much better if you explained what you are trying to achieve so that people can suggest other approaches.