1

I have a base class Collection as follows:

class Collection {
    protected:
    int size_;

    public:

    //virtual size()
    virtual int size() = 0;
    //virtual destructor
    virtual ~Collection();
    //copy constructor for deep copy
    Collection();
    //virtual copy constructor
    Collection(const Collection& set);
    //virtual method copy()
    virtual Collection* copy()=0;
    //virtual operator[]
    virtual int& operator[](int pos) = 0;
    //virtual operator=
    virtual Collection& operator=(Collection &rhs) = 0;
    //virtual add()
    virtual Collection& add(int number) = 0;
    bool contains(int i);
};

In a derived class Array, I need to implement the pure virtual assignment operator. In Array.h, it is declared as:

public:
    virtual Array& operator = (Collection &rhs);// assignment operator

In Array.cpp, the code is:

Array& Array::operator=(Collection &rhs) 
{
    Array pArr = dynamic_cast<Array&>(rhs);
    if(this == &pArr)
    {
        return *this;
    } // handling of self assignment.

    delete[] pa; // freeing previously used memory
    pa = new int[pArr.size_];
    size_ = pArr.size_;
    memcpy(pa, pArr.pa, sizeof(int) * size_);
    return *this;
}

After compiling, the error is:

undefined reference to `Collection::operator=(Collection&)'

I searched related webpages, usually it is because of the signatures are not matching. However, I could not figure out my problem here.

EDIT: The code in my main() that generates the problem is:

 Array a1; // create an array object, size 10
 Array a2; // create an array object, size 10
 a1.add(1); // add data to array
 a1.add(2);
 a1.add(3);
 a1[3] = 4;
 a2.add(4);
 a2 = a1;
HHY
  • 23
  • 3
  • 1
    The Array's `operator=` needs to return a `Collection&`, not an `Array&`. You can't change the signature of virtual methods, and that includes return types. Also, this line: `Array pArr = dynamic_cast(rhs);` should be `Array &pArr = dynamic_cast(rhs);` instead (note the extra `&` on `pArr`) to avoid creating a copy of the array. Also, `rhs` should be passed by `const` reference (`const Collection &rhs`), then the `dynamic_cast` becomes `const Array &pArr = dynamic_cast(rhs);` And your operator is not exception-safe (if `new[]` fails, `pa` is left invalid). – Remy Lebeau Apr 21 '17 at 01:20
  • Cannot reproduce. http://coliru.stacked-crooked.com/a/e7b8d283b674d489 . You must have some other code calling `Collection::operator=`. – aschepler Apr 21 '17 at 01:21
  • 1
    @RemyLebeau Returning `Array&` from `Array::operator=` is valid because it's a covariant return type. – aschepler Apr 21 '17 at 01:22
  • @aschepler: yes, but not all C++ compilers support covariant return types. If `operator=` were not virtual, this wouldn't be an issue. – Remy Lebeau Apr 21 '17 at 01:35
  • 1
    Keep in mind, unless you change it, the default implementation of `Array& Array::operator=(Array const&)` and the move version, both invoke the base class assignment operator first. So if you do an array-to-array assignment, it'll need to use the base class method. – Dave S Apr 21 '17 at 01:35
  • 1
    @RemyLebeau Really? Who's the offending compiler? – aschepler Apr 21 '17 at 01:46
  • @Remy Lebeau, I agree with you about the "const". And yes, this operator is not exception-safe. Could you give some suggestion about that? However, I am still not sure whether the ampersand is needed for "Array pArr = dynamic_cast(rhs)". In addition, i think "Virtual method must be defined in ancestor class with same argument signature as derived class method (except return type Base& or Base* is matched by Derived& and Derived*)". – HHY Apr 21 '17 at 02:16
  • @aschepler, thank you for your help. I think there was something wrong with my client code in main function. I am not sure what exactly the problem is. I just modified it based on the code in your main(). Thank you again! – HHY Apr 21 '17 at 02:19
  • @aschepler, I updated my main code in the question. Could you explain why I have to use "Collection& c1 = arr1; Collection& c2 = arr2; c1 = c2;" ? Is it because in "Array& operator = (const Collection &rhs)", the argument is of Collection& type? Is there a way to make my main code mentioned in the question work as well? Thank you. – HHY Apr 21 '17 at 02:36
  • @HHY: exception safety can be achieved using the [copy-and-swap idiom](http://stackoverflow.com/questions/3279543/). And `Array pArr = ...` without `&` makes a *copy* of the source, which you don't want to do in this case, as `if (this == &pArr)` will then always be false. You need a reference to the source instead. – Remy Lebeau Apr 21 '17 at 03:00
  • @ Remy Lebeau. I changed that line to `Array &pArr = dynamic_cast(rhs);` , then this error came out: binding 'const Array' to reference of type 'Array&' discards qualifiers. However, with `Array pArr = dynamic_cast(rhs);` (no &). There is no problem. Could you explain the problem of the former code? Thanks. – HHY Apr 21 '17 at 03:18

0 Answers0