views:

62

answers:

1

Hello, I want to make chain-calling like jquery-way in c++. The sample:

$('#obj').getParent().remove();

So, as I understand, each method of the class should return the pointer to himself (this).

Everything is okay until I call base-derived methods. The code:

class Base
{
   Base *base1() { return this; }
   Base *base2() { return this; }
};

class Derived : Base
{
   Derived *derived1() { return this; }
   Derived *derived2() { return this; }
};

Derived *obj = new Derived();
obj->derived1()->derived2(); // Everything is okay
obj->derived1()->base1()->derived2(); // Fail at second step

Sure, the base1 returns the pointer for the Base. Are there any ways to make automatic casting?


UPD: Maybe that's possible with macros? Like

#define CORRECT_RETURN (this)

and

Base::base1() {
   return CORRECT_RETURN;
}

Something in this way. Or the compiler will not look at such construction?

+2  A: 

Yes. Override the base1 and base2 methods in Derived to change their return value from Base* to Derived*, e.g.

class Derived : Base
{
   Derived *base1() { return this; }
   Derived *base2() { return this; }
   Derived *derived1() { return this; }
   Derived *derived2() { return this; }
};

This is called covariance of return types and is legal in C++.

Assuming you want to actually use some functionality implemented in the base class methods without repeating it, you would do something like this:

class Derived : Base
{
   Derived *base1() { Base::base1(); return this; }
   Derived *base2() { Base::base2(); return this; }
   Derived *derived1() { return this; }
   Derived *derived2() { return this; }
};

Before you ask, no, you cannot create a situation where each derived class of the base automatically overrides the base1 and base2 methods using return types with the appropriate covariance. You have to do it manually every time, or else write a lot of scaffolding code to make it look like that's what's happening, which is usually more trouble than its worth.

Tyler McHenry
don't forget virtual on base. As defined, you're doing hiding, so you won't get polymorphism.
Merlyn Morgan-Graham
Virtual methods are probably a good idea with a hierarchy like this, but are not actually required here for this to work. `obj` is a `Derived*`, so `obj->derived1()` is a `Derived*`, so `obj->derived1()->base1()` calls `Derived::base1` (which actually returns a `Derived*`) whether or not `base1` is virtual.
Tyler McHenry
@tyler-mchenry good answer. Could you look at update, please?
Ockonal
It's never going to be possible by modifying the base class, since there could be an infinite number of derived classes. Macros will not help you. If you don't want to use covariance, the only other answer is to just do a standard downcast: `dynamic_cast<Dervied*>(obj->derived1()->base1())->derived2()`, but I assumed you already knew about that and wanted something syntactically nicer.
Tyler McHenry
@tyler-mchenry okay, thanks for the answer.
Ockonal