Reputation: 252
I have a base class Base
and a class that inherits it called Derived
. Class Base
has a virtual function returnPtrToSelf()
that returns a pointer to itself. Derived
has its original member function derivedFunc()
which Base
has not.
#include <iostream>
class Base {
public:
virtual Base* returnPtrToSelf() {
return this;
}
};
class Derived : public Base {
public:
void derivedFunc() {
std::cout << "i am derived" << std::endl;
}
}
int main() {
Derived d;
d.derivedFunc(); // works
d.returnPtrToSelf()->derivedFunc(); // ERROR
((Derived*)d.returnPtrToSelf())->derivedFunc(); // works
}
The error will not go away unless I implement Derived
's own returnPtrToSelf()
that returns a Derived*
.
I am making a lot of derived classes and think it is tedious to implement an original version of this function for each derived class. Is there a more convenient way of fixing that error other than this tedious way?
Upvotes: 1
Views: 2150
Reputation: 1
"I am making a lot of derived classes and think it is tedious to implement an original version of this function for each derived class. Is there a more convenient way of fixing that error other than this tedious way?"
I'd say that's a classical case to use the Template Method Pattern:
class Base {
public:
void func() {
funcImpl();
}
virtual ~Base() {}
protected:
Base() {}
virtual void funcImpl() = 0;
};
class DerivedA : public Base {
public:
DerivedA() {}
protected:
void funcImpl() {
// DerivedA special implementation
}
};
class DerivedB : public Base {
public:
DerivedB() {}
protected:
void funcImpl() {
// DerivedB special implementation
}
};
Call in main would look like
int main() {
DerivedA dA;
DerivedB dB;
dA.func();
dB.func();
}
This is especially useful, if every class derived from Base
should contribute some specialized piece for some more complex logic going on in Base::func()
.
This could be achieved in a similar way using a templated base class (without need for the vtable overhead), and merely encapsulating the cast applied in your main()
function:
template<typename Derived>
class Base {
public:
void func() {
static_cast<Derived*>(this)->funcImpl();
}
protected:
Base() {}
};
class DerivedA : public Base<DerivedA> {
public:
DerivedA {}
protected:
friend class Base<DerivedA>;
void funcImpl() {
// DerivedA special implementation
}
};
class DerivedB : public Base<DerivedB> {
public:
DerivedB {}
protected:
friend class Base<DerivedB>;
void funcImpl() {
// DerivedB special implementation
}
};
This is also well known as the CRTP -> Curiously Recurring Template Pattern.
Upvotes: 0
Reputation: 302718
No, there isn't. If derivedFunc
is really something that anything that inherits from Base
should support, then that should be reflected in Base
:
struct Base {
virtual void func() = 0;
};
struct Derived : Base {
void func() override { std::cout << "i am derived" << std::endl; }
};
Base* b = new Derived;
b->func();
If derivedFunc
is only applicable to a Derived
, then it wouldn't make any sense to be able to access it from Base
anyway. What if Base
were a AnotherDerived
instead? In those cases where you really need to call derivedFunc
, just have your functions take a Derived*
(or Derived&
) instead of a Base*
(or Base&
).
As a last resort, if there's really some case where you absolutely need to call derivedFunc
on a Derived
uniquely, then there's always:
void maybeCallDerivedFunc(Base* b) {
if (auto d = dynamic_cast<Derived*>(b)) {
d->derivedFunc();
}
}
Upvotes: 1