Domanda

I have a BaseClass with a method that returns a class object, and i have a DerivedClass. Now when I have a DerivedClass object and call the method defined in the BaseClass, the returning value is ob type BaseClass, and unfortunately not of type DerivedClass.

class BaseClass {
public:
  typeof(*this) myMethod1() {return *this;} // nice if that would work
  BaseClass& myMethod2() {return *this;}
  BaseClass myMethod3() {return BaseClass();}
};
class DerivedClass : public BaseClass {};

DerivedClass tmp;
tmp.myMethod1();
tmp.myMethod2();
tmp.myMethod3();
// all three methods should return an object of type DerivedClass,
// but really they return an object of type BaseClass

So what I wish to achieve is to use methods of the superclass, but with return types of the derived class(automatic casting?). myMethod1() was the only thing I could think of, but it doesn't work.

I've searched but didn't find anything satisfying.

È stato utile?

Soluzione 4

Thanks for the answers. Maybe my question was not clear enough, but I could solve my problem myself by just adding another Constructor.

To clarify: I had the BaseClass with a member method operator+() and the DerivedClass (without that member method). Now when I called the DerivedClass' operator+(), the return type was of BaseClass. I could simply add the operator+() to the DerivedClass, but instead, adding the Copy-Constructor which accepts a argument of the super-type (here BaseClass) solved the problem and the return types became correct automatically:

DerivedClass(const BaseClass& src) : BaseClass(src) {}

Altri suggerimenti

You would like to use the CRTP (http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern) pattern :

template <class Derived>
class BaseClass {
public:
  Derived *myMethod1() {return static_cast<Derived *>(this);}
  Derived& myMethod2() {return static_cast<Derived&>(*this);}
};
class DerivedClass : public BaseClass<DerivedClass> {};

DerivedClass tmp;
tmp.myMethod1();
tmp.myMethod2();

Just use covariant return type rule, and be done.

To restate it: If you return by pointer or reference, your override can explicitly have a return type derived from the type returned in the base class, and it is a valid virtual override.

10.3 Virtual functions §7

The return type of an overriding function shall be either identical to the return type of the overridden function or covariant with the classes of the functions. If a function D::f overrides a function B::f, the return types of the functions are covariant if they satisfy the following criteria:
— both are pointers to classes, both are lvalue references to classes, or both are rvalue references to classes112
— the class in the return type of B::f is the same class as the class in the return type of D::f, or is an unambiguous and accessible direct or indirect base class of the class in the return type of D::f
— both pointers or references have the same cv-qualification and the class type in the return type of D::f has the same cv-qualification as or less cv-qualification than the class type in the return type of B::f.

If you do not actually want to make it virtual, you can just define the functions in the derived class and call back to the base class.

If you have multiple derived classes, you might consider using the CRTP to make that go faster:

template <class X>
struct CRTP : BaseClass {
  X& myMethod1() {return static_cast<X&>(*this;)} // covariant maybe-virtual
  X& myMethod2() {return static_cast<X&>(*this;)} // covariant maybe-virtual
  X myMethod3() {return X();} // Not virtual
};
struct DerivedClass1 : CRTP<DerivedClass1> {};
struct DerivedClass2 : CRTP<DerivedClass2> {};
struct DerivedClass3 : CRTP<DerivedClass3> {};

I can't comment on your answer, although this should be a comment and not an answer.. But anyway. I'll start by saying that I'm not really sure about this, but I think that your solution using a "Base to Derived" constructor has a couple of issues.

First, if you would have any members in your DerivedClass that's not members of your BaseClass, then those would be initalised to their default values when the DerivedClass(const BaseClass& src) is called. This may normally not be a problem, but this is probably implicitly called when you use the

DerivedClass someObject = ++someDerivedClassObject;

the compiler probably calls it as:

DerivedClass someObject = DerivedClass(++((BaseClass)someDerivedObject));

Secondary, since this is creating a new object, you might get unexpected results if you ever pass a DerivedClass-object by-reference or by-address to some function and expect a side-effect, as the ++ creates a new object. This might, however be exactly the behaviour that you are looking for if you have a postfix increment (operator++(int)).

The answers given already in this thread are the ones I would recommend myself. Not sure what you mean with "your baseclass is already a template".

PS. As I've said, this is not by the rules of Stack Overflow a good answer, but I just created an account, so I can't comment on other peoples answers.. Maybe someone can confirm and move this?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top