How and when would I call a super class method? Please referr to code segment for the two options:
class SuperClass {
public:
void method();
};
class SubClass : public SuperClass {
public:
void someOtherMethdo(){
this->method();
SuperClass::method();
}
};
using this->method() you call a function that is either implemented in your superclass, either by your own class.
When using superClass::method(), you make sure to call the one implemented by your parent.
#include <iostream>
#include <string>
class A {
public:
void func() {
std::cout << "A func" << std::endl;
}
};
class B : A {
public:
void func() {
std::cout << "B func" << std::endl;
}
void exec() {
this->func();
A::func();
}
};
int main() {
B b;
b.exec();
return 0;
}
This sample code will output
B func
A func
this->method();
...calls method on the derived class (and is the same as writing simply method();). This could call the inherited method from the parent (and does in the example), or it could call an overridden version in the child class (and will, if one exists).
SuperClass::method();
...will always call the method on the parent. This syntax is often used within an override in the child, when you want to keep and extend the functionality of the parent class method. E.g.
Class SubClass: public SuperClass {
//...
void method() {
SuperClass::method();
//...
}
};
Note that if you use the first syntax in this second case, you'll get recursion.
Note also that this has nothing to do with virtual methods. Marking a method as virtual means that, when the method is called via a base class pointer, the most-derived class method available will be called. In the code above, it makes no difference whether any of the methods are virtual since there are no base class pointers involved.
this->method
Will default to the local implementation in your derived class first, if that one isn't present, it will take the superclass method. If that one is not present it will give a compilation error.
superClass::method()
Will always direct to the method in your superclass
In most cases you want this->method. superClass::method() Is usefull when part of a method is implemented in the superclass and you want to extend it in the derived class. something like:
Class SubClass : public SuperClass {
public:
void someOtherMethdo(){
SuperClass::someOtherMethdo();
//Rest of the method
}
}
this->method() leaves room for ambiguity under certain circumstances (e.g. if more than one ancestor defines method with this signature), but at the same time allows method to be called no matter where exactly it is defined. If method is virtual it will call the most-derived version.
SuperClass::method() is explicit. It will either call that specific method or give a compiler error.
In this particular example, no difference.
If the method is virtual:
this->method() will call the function dynamically (call the top-most implemented version of the class)
SuperClass::method() results in a static call.
this->method(); call parent's in your case or if it's virtual - call the top of implemented functions in vtable. SuperClass::method(); will call parent's method.
Related
Imagine a huge code base with many many inheritance. At some point a line comes in your way in the class you have to work with.
inherited::Load();
This is do what it says. It loads the base object into memory.
inherited is a typedef for the base class.
However the actual parent class does not have a Load method.
As a quick example:
class Base {
public:
Base() {};
void Load() {
cout << "Base ok" << endl;
}
};
class Derived : public Base {
public:
Derived() {};
};
class MostDerived : public Derived {
public:
MostDerived(){};
void Load() {
Derived::Load();
cout << "Child ok"<< endl;
}
};
Here, if we call MostDerived.Load() it will call its parent's Load method, but the Derived class doesn't have its own Load, only Base's Load method.
What is actually going on here? Why there is no compilation issue?
Is the Derived class copies all the method of the base, so it will have a Load method what is prints "Base ok"? Or does Derived simply calls forward the Base method?
I found a related question Do ALL virtual functions need to be implemented in derived classes? and the answer says
It inherits the bar implementation from its ancestor class.
For me it still miss leading that explicitly calling the Derived::Load() method works. However, there is only a Base::Load() method exists.
What is actually going on here? Why there is no compilation issue? Is the Derived class copies all the method of the base, so it will have a Load method what is prints "Base ok"?
Yes. A derived class inherits all methods from the base class. (yes really all of them, whether it can access them depends on the access specified for the methods).
For me it still miss leading that explicitly calling the Derived::Load() method works. However, there is only a Base::Load() method exists.
Sloppy speaking the Derived:: only tells the compiler to look for names accesible from Derived. As Derived does inherit from Base, it does have a Load method.
Maybe your confusion can be cleared up a bit by noting that Derived::Load indeed does refer to Base::Load:
#include <type_traits>
#include <iostream>
struct Base {
void Load() {}
};
struct Derived : Base {};
int main() {
std::cout << std::is_same_v< decltype(&Derived::Load), void (Derived::*) ()>;
std::cout << std::is_same_v< decltype(&Derived::Load), void (Base::*) ()>;
}
This prints 01, because Derived::Load is indeed a method of Base.
I hope the example is not adding confusion ;). It uses std::is_same to see if two types are the same. &Derived::Load gives me a member function pointer to the Load method in Derived whose type I infer via decltype. I compare that once to pointer to method of Derived and then to pointer to method of Base. It turns out that Derived::Load is a method of Base.
I have a class derived from a parent class. It calls a member from the parent class. However a behaviour of the member need to be revised due to the functional requirement of the child class. I wrote the code in this way:
class parentClass
{
public:
void memberA()
{
memberB();
}
void memberB()
{
behaviorParent;
}
};
class childClass:public parentClass
{
public:
void memberB()
{
behaviorChild;
}
};
int main()
{
child naughty;
naughty.memberA();
}
I'm expecting a behaviorChild come as the result. However instead, the program gives me an behaviorParent rather than behaviorChild. Do you know why is that? And, how to fix it without replicating the code of parent member?
parentClass::memberB is not declared virtual. The compiler therefore assumes, that the call to memberB from parentClass::memberA refers to parentClass::memberB.
To tell the compiler that the call to memberB should refer to a memberB defined in a derived class if such a function exists, declare parentClass::memberB as
virtual void memberB();
you dont have child::A() in the derived class. So it'll be the base version. If you want something else you need to override child:A() in derived class
You're using memberA() method from your base class. This method in base class cannot have any idea of what have you implemented in the child. That's why it still calls memberB() from base class.
If you don't want to change your base class code you will have to override memberA() method in your child class.
You can find an example of overriding in C++ here.
I'd like to build a factory for my Source-Plugins like that:
class PluginFactory {
public:
PluginFactory(){};
virtual ~PluginFactory(){};
static MySource* getSourceById(int id, ParameterList& pList){
switch (id){
case 1:
return new StringSource(pList);
default:
std::cout << "Unknown PluginId!" << std::endl;
return nullptr;
}
}
};
MySource cannot be abstract like usual in the pattern because it will later be used in a template class.
When I call a method of the returned MySource* I get the method of the superclass MySource instead of the overridden method of the subclass StringSource.
Any ideas how to fix this?
EDIT:
I declared the superclass method as vritual:
MySource{
...
virtual std::streamsize read(char* s, std::streamsize n){
...
}
};
I added the override command to the subclasses' read-Method:
class StringSource: public MySource {
...
std::streamsize read(char* s, std::streamsize n) override
{
...
}
};
But it still uses the superclass method. There has to be another reason...
Btw. I put the Source-Class into a boost::iostream::filtering_istream like this:
MySource* source = PluginFactory::getSourceById(1, pluginList[0].second);
boost::iostreams::filtering_istream in;
in.push(*source);
So I don't call the read-method myself.
The problem is this:
in.push(*source);
According to the documentation, this will copy the argument. Since your base class is copyable and not abstract, you encounter the slicing problem where only the base sub-object is copied.
You should be able to fix it by passing a reference wrapper instead:
in.push(std::ref(*source));
I would suggest that you make the base class abstract (or at the very least uncopyable), to prevent the possiblity of slicing. I don't understand your reason for not making it abstract; but whatever requires it to be concrete sounds scary and error-prone.
UPDATE: Since you made it concrete just so you could pass it to this function, you should make it abstract again, and pass a reference wrapper instead.
When I call a method of the returned MySource* i get the method of the superclass MySource instead of the overridden method of the subclass StringSource.
I'm not sure this will work (without seeing any relevant code), but it sounds like you need to declare your superclass method (the one you call) as virtual, so that the compiler knows to run the overridden version (in this case, of StringSource), rather than the superclass version.
Hope this helps!
The method in MySource that you call must be virtual otherwise, the one in the derived class doesn't override but, instead, hides it. For instance,
class Base {
public:
void foo() const { std::cout << "Base::foo()\n"; }
virtual void bar() const { std::cout << "Base::bar()\n"; }
};
class Derived : public Base {
public:
void foo() const { std::cout << "Derived::foo()\n"; } // hides Base::foo
void bar() const { std::cout << "Derived::bar()\n"; } // overrides Base::bar
};
Derived d;
Base& b = d;
d.foo(); // outputs Derived::foo()
b.foo(); // outputs Base::foo()
b.bar(); // outputs Derived::bar()
If you're using C++11, I would advise to use the override keyword in the declaration of Derived::bar():
void bar() const override { std::cout << "Derived::bar()"; }
More precisely, you should use override in the declaration of all derived methods that are meant to override the one in the base class. If you make a mistake and the method in the derived class doesn't override any method in the base, then the compiler will raise an error.
Herb Sutter explains the issues here.
Update: After the OP's addition of more information.
Another possible reason for the issue is as follows. If the base class is copied (e.g. when it's passed to a function by value), then the copy looses information on the dynamic type. For instance, reconsider the example above and these functions:
void call_bar_pass_by_value(Base x) {
x.bar();
}
void call_bar_pass_by_reference(const Base& x) {
x.bar();
}
Then, calling them with b gives:
call_bar_pass_by_value(b); // outputs Base::bar()
call_bar_pass_by_reference(b); // outputs Derived::bar()
I'm not familiar with Boost.Iostreams but looking at the reference documentation of filtering_stream::push() here we can see that this function does take its argument by reference. Hence, the problem that I just described doesn't happen here. However, this function might call another one which call another one ... and one of them might make take the argument by value (or make a copy of it).
The OP states that "MySource cannot be abstract like usual in the pattern because it will later be used in a template class". This suggests that an attempt to copy the object is made.
I don't know what to advise now but just to test my theory above (it doesn't solve the issue) I would temporarily make MySource's copy constructor protected to see whether Boost.Iostreams tries to copy MySource. If so, then the code will fail to compile.
If I have the following override of a virtual event:
void derivedClass::method(event)
{
// my stuff
baseClass::method(event); // <--
}
what does the // <--- line does? What does it call? I don't think it calls the base class' method because it's virtual (so no body)
As you are suggesting, it calls the base class' method. The fact that it is virtual it only means it can be overridden and still access to the derived class' method from a pointer/reference to the base class.
The reason to do that can be easily seen with an example:
class Base {
public:
virtual void foo() {
/* do some generic stuff */
}
};
class Derived : public Base {
public:
void foo() {
/* do some specific stuff */
/* if you also want to do the generic stuff,
you can call the same method from the base class. */
Base::foo();
}
}
It might be the case that you do not want to do the generic stuff for Derived class. Then you would just remove the call to Base::foo().
Here you have a good reference on virtual methods.
It does call the base class method. Yes, the derived method is being called "polymorphically", but it can call its base method using Base::method
When qualified name (<class name>::<method name>) is used in a class method call, the method is called directly, non-virtually. In your example, baseClass::method is called. Since qualified name is used, the fact that the method is virtual means absolutely nothing and makes no difference whatsoever.
considering a simple inherited class:
class Base
{
void func() {
cout << "base" << endl;
}
};
class Derived : public Base
{
void func() {
cout << "derived" << endl;
}
};
if I run Derived::func() I get
derived
I would like to modify this code to get
base
derived
Something more similar to an extension than an overriding.
I've been able to get something similar with constructors, but not with normal functions.
Many thanks,
Lucio
class Derived : public Base
{
void func() {
Base::func(); // Call the base method before doing our own.
cout << "derived" << endl;
}
};
To access the base-class function from the derived class, you can simply use:
Base::func();
In your case, you would have this as the first line of the derived implementation of func().
Using Base::func(); is correct like a few others already stated.
Remember the constructor for the base class will always get called first, then the constructor for the derived class.
You've talked about constructor, a derived class's constructor will call base class's one, no matter whether you use an inherited constructor, it makes sense because a derived class should be able to construct the members inherited from the base class. And by default, constructor wouldn't be inherited.
But, the "normal" method goes the much different way.
First, please sure that in most of the time, it's not necessary for a method in derived class to call the same-name method in base class, and on the contrary, it will cover base class's one, although it did inherit it.
So if you really want to call base class one, you should tell complier explicitly. Using baseclass::somemethod will fulfill your request.
You can't do so.
You'll have to do like
Void derived:: func()
{
this->func(); /*you should use 'this pointer' to
access the base class functions*/
cout<<"derived";
}