C++ Overload Operator = for Pointers does not work

2019-08-29 16:59发布

问题:

I am trying to implement a template Class with an Operator Overload for = so far it works for non pointer elements. For Pointer Elements it doesn't work exactly as I expect it to, so my question is why this is sow and how do I force c++ do it as I want.

My template Class:

template <class T>
class IBag {
public:
    T _val;
    void Set(T val) { _val = val; } 
    T Get() { return _val; }

    IBag& operator=(T val) {
        this->Set(val);
        return *this;
    }

    operator T() {
        return this->Get();
    }
};

How it works using the IBag Class:

class IBagExample
{
   void showExample() {
        IBag<QString*> pbag;
        pbag = new QString("Blub"); // This works !
    }
};

how it does not compile:

class IBagExample
{
   void showExample() {
        IBag<QString*> pbag = new QString("Blub"); // This doesn't compile !
    }
};

The compiler Error I get is :

error: no viable conversion from 'QString *' to 'IBag<QString *>'
    IBag<QString*> pbag2 = new QString("Blub");
                   ^       ~~~~~~~~~~~~~~~~~~~

For me it seems the same, maybe I need to tell the compiler something to understand what type of pointer is now going to be pushed into the pbag. But I have no Idea how to do that.

Using the operator overload like

IBag<QString*> pbag; pbag = new QString("Blub"); // This does compile !

seems just ridiculous.

(Note:The IBag example is just a simplification of the Code I am trying to implement.)

Thanks a lot,

回答1:

IBag<QString*> pbag = new QString("Blub");

This doesn't actually call the assignment operator, it calls a constructor. You need to define that something like:

template <class T>
class IBag {
public:
    IBag( const IBag& rhs )
    {
        // ....
    }

};

or:

    IBag( const T& rhs )
    {
        // ....
    }


回答2:

Assignment is not construction. A copy assignment operator doesn't handle construction (even if the = in an assignment looks suspiciously like the = in a declaration with copy initialization). Either define a suitable constructor or use C++11 braces initialization, e.g.

auto pbag2 = IBag<QString*>{ new QString("Blub") };

Disclaimer: code untouched by compiler's hands.


Issues with the code:

  • setters and getters are in general a design smell, a Java-ism, even if they sometimes are useful,

  • public data members are also a design smell for a class with an invariant (such as non-null pointers),

  • a public data member with a setter and a getter, that's not meaningful,

  • you need to take charge of copying (rule of three, rule of zero), and

  • you need to make a decision on supporting constness, and do The Right Thing™ (whatever it may be).


For a logical interface, as this is, also consider adding a virtual destructor. That enables RTTI via the interface. E.g. deleting an object via the interface, or dynamic casting to some other interface or implementation class.