Question

I am trying to support a copy function in some of my classes and to do so I created a base class (an interface). But in addition to that class I have another class that inherits from it and needs to override the "copy" function and provide a new return type. The way that I am copying the class is by using a wrapper class to automatically delete the pointer to the newly allocated object when it is no longer used. It is a templated class which does not qualify as a covarient type. What I just described looks a lot like this:

template <T>
struct BASE {
    virtual PTR<BASE> copy() const = 0;
};

template <Y>
struct DERIVED : public BASE<Y> {
     virtual PTR<DERIVED> copy() const = 0; // ERROR: PTR<DERIVED> not a covarient type to PTR<BASE>.
};

Knowing that this is not legal in C++, I was wondering if I could do something similar to this such as:

template <T>
struct DERIVED : public BASE<T> {
    virtual PTR<DERIVED> DERIVED::copy() const = 0; // Derived classes should override this function and act as if "PTR<BASE<T>> BASE<T>::copy() const" does not exist.

    private: // hide function so that "PTR<DERIVED>" function is called, but when dealing with the base class call the following function.
    PTR<BASE<T>> BASE<T>::copy() const {
         return PTR<BASE<T>>((BASE<T>*)DERIVED::copy()->GetAndRelease()); // Convert the "PTR<DERIVED>" object to a "PTR<BASE<T>>" object.
    }
};

The code above does not compile because you cannot name the class your in when defining it in a class. EX: can't do "DERIVED::copy" while in the class and defining a function, at least G++ gives me an error when I do it. It is worth mentioning that the "PTR" class mentioned works something like this:

template <T>
struct PTR {
    PTR(T* ptr); // set the pointer to the data;
    ~PTR(); // destroy the object pointed to by "ptr";

    T* get(); // get the pointer to the data;
    T* GetAndRelease(); // just to simplify the example, this function returns the pointer and makes it so that the class does not delete the pointer when it is deconstructed.

    private:
    T* ptr;
}
Was it helpful?

Solution

You can't overload based on the return type. The simple solution is to not make the copy() function the virtual interface but rather have it just call the virtual interface:

class Base {
    Base* do_copy() const = 0;
public:
    smart_ptr<Base> copy() const { return smart_ptr<Base>(this->do_copy()); }
};
class Derived {
     Derived* do_copy() const { return new Derived(*this); }
public:
     smart_ptr<Derived> copy() const { return smart_ptr<Derived>(this->do_copy()); }
};

The idiom of not making virtual functions public is used quite consistently in the standard library (I think the exception is std::exception::what()). It also conveniently side-steps the issue of an override hiding other overloads (see, e.g., the put() and do_put() members of std::num_put<...>).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top