Why does calling a method in my derived class call the base class method?
There's a difference between new
and virtual
/override
.
You can imagine, that a class, when instantiated, is nothing more than a table of pointers, pointing to the actual implementation of its methods. The following image should visualize this pretty well:
Now there are different ways, a method can be defined. Each behaves different when it is used with inheritance. The standard way always works like the image above illustrates. If you want to change this behavior, you can attach different keywords to your method.
1. Abstract classes
The first one is abstract
. abstract
methods simply point to nowhere:
If your class contains abstract members, it also needs to be marked as abstract
, otherwise the compiler will not compile your application. You cannot create instances of abstract
classes, but you can inherit from them and create instances of your inherited classes and access them using the base class definition. In your example this would look like:
public abstract class Person
{
public abstract void ShowInfo();
}
public class Teacher : Person
{
public override void ShowInfo()
{
Console.WriteLine("I am a teacher!");
}
}
public class Student : Person
{
public override void ShowInfo()
{
Console.WriteLine("I am a student!");
}
}
If called, the behavior of ShowInfo
varies, based on the implementation:
Person person = new Teacher();
person.ShowInfo(); // Shows 'I am a teacher!'
person = new Student();
person.ShowInfo(); // Shows 'I am a student!'
Both, Student
s and Teacher
s are Person
s, but they behave different when they are asked to prompt information about themselves. However, the way to ask them to prompt their information, is the same: Using the Person
class interface.
So what happens behind the scenes, when you inherit from Person
? When implementing ShowInfo
, the pointer is not pointing to nowhere any longer, it now points to the actual implementation! When creating a Student
instance, it points to Student
s ShowInfo
:
2. Virtual methods
The second way is to use virtual
methods. The behavior is the same, except you are providing an optional default implementation in your base class. Classes with virtual
members can be instanciated, however inherited classes can provide different implementations. Here's what your code should actually look like to work:
public class Person
{
public virtual void ShowInfo()
{
Console.WriteLine("I am a person!");
}
}
public class Teacher : Person
{
public override void ShowInfo()
{
Console.WriteLine("I am a teacher!");
}
}
The key difference is, that the base member Person.ShowInfo
isn't pointing to nowhere any longer. This is also the reason, why you can create instances of Person
(and thus it does not need to be marked as abstract
any longer):
You should notice, that this doesn't look different from the first image for now. This is because the virtual
method is pointing to an implementation "the standard way". Using virtual
, you can tell Persons
, that they can (not must) provide a different implementation for ShowInfo
. If you provide a different implementation (using override
), like I did for the Teacher
above, the image would look the same as for abstract
. Imagine, we did not provide a custom implementation for Student
s:
public class Student : Person
{
}
The code would be called like this:
Person person = new Teacher();
person.ShowInfo(); // Shows 'I am a teacher!'
person = new Student();
person.ShowInfo(); // Shows 'I am a person!'
And the image for Student
would look like this:
3. The magic `new` keyword aka "Shadowing"
new
is more a hack around this. You can provide methods in generalized classes, that have the same names as methods in the base class/interface. Both point to their own, custom implementation:
The implementation looks like the one, you provided. The behavior differs, based on the way you access the method:
Teacher teacher = new Teacher();
Person person = (Person)teacher;
teacher.ShowInfo(); // Prints 'I am a teacher!'
person.ShowInfo(); // Prints 'I am a person!'
This behavior can be wanted, but in your case it is misleading.
I hope this makes things clearer to understand for you!
Why is base class method called instead of derived class method?
When you use the new
modifier you are specifically saying that the method is not part of the virtual dispatch chain for that hierarchy, so calling the method by the same name in the base class will not result in redirection to the child class. If you mark the method with override
instead of new
then you will see the virtual dispatch that you are expecting to see.
You will also need to remove virtual
from the derived class's method as you cannot mark an override
method as virtual
(it already is).
If you really don't want to override the method then it may be more appropriate, in your situation, to not use inheritance at all. You may simply want to use interfaces exclusively:
public interface IFoo
{
void Foo();
}
public class A : IFoo
{
public void Foo()
{
Console.WriteLine("I am A, hear me roar!");
}
}
public class B : IFoo
{
public void Foo()
{
Console.WriteLine("I am B, hear me roar!");
}
}
private static void Main(string[] args)
{
IFoo foo = new A();
foo.Foo();
foo = new B();
foo.Foo();
Console.WriteLine();
Console.WriteLine("Press any key to exit . . .");
Console.ReadKey(true);
}
Base class method being called instead of derived, even when passed by reference
The argument to the constructor is fine. It is an object of type B
passed by reference to the A
subobject. The problem is that you copy the A
subobject only (and not the derived object) into the member variable a
. Then when you call a.method()
there is only a base object there, so the base function is called.
The solution is to make the member variable be a pointer or a reference (and not a copy) of the argument. (Note that in either case, you will then need to make sure that the object you pass in, will live at least as long as the AnotherClass
object.
Call base class method from derived class object
You can always(*) refer to a base class's function by using a qualified-id:
#include <iostream>
class Base{
public:
void foo(){std::cout<<"base";}
};
class Derived : public Base
{
public:
void foo(){std::cout<<"derived";}
};
int main()
{
Derived bar;
//call Base::foo() from bar here?
bar.Base::foo(); // using a qualified-id
return 0;
}
[Also fixed some typos of the OP.]
(*) Access restrictions still apply, and base classes can be ambiguous.
If Base::foo
is not virtual
, then Derived::foo
does not override Base::foo
. Rather, Derived::foo
hides Base::foo
. The difference can be seen in the following example:
struct Base {
void foo() { std::cout << "Base::foo\n"; }
virtual void bar() { std::cout << "Base::bar\n"; }
};
struct Derived : Base {
void foo() { std::cout << "Derived::foo\n"; }
virtual void bar() { std::cout << "Derived::bar\n"; }
};
int main() {
Derived d;
Base* b = &d;
b->foo(); // calls Base::foo
b->bar(); // calls Derived::bar
}
(Derived::bar
is implicitly virtual even if you don't use the virtual
keyword, as long as it's signature is compatible to Base::bar
.)
A qualified-id is either of the form X :: Y
or just :: Y
. The part before the ::
specifies where we want to look up the identifier Y
. In the first form, we look up X
, then we look up Y
from within X
's context. In the second form, we look up Y
in the global namespace.
An unqualified-id does not contain a ::
, and therefore does not (itself) specify a context where to look up the name.
In an expression b->foo
, both b
and foo
are unqualified-ids. b
is looked up in the current context (which in the example above is the main
function). We find the local variable Base* b
. Because b->foo
has the form of a class member access, we look up foo
from the context of the type of b
(or rather *b
). So we look up foo
from the context of Base
. We will find the member function void foo()
declared inside Base
, which I'll refer to as Base::foo
.
For foo
, we're done now, and call Base::foo
.
For b->bar
, we first find Base::bar
, but it is declared virtual
. Because it is virtual
, we perform a virtual dispatch. This will call the final function overrider in the class hierarchy of the type of the object b
points to. Because b
points to an object of type Derived
, the final overrider is Derived::bar
.
When looking up the name foo
from Derived
's context, we will find Derived::foo
. This is why Derived::foo
is said to hide Base::foo
. Expressions such as d.foo()
or, inside a member function of Derived
, using simply foo()
or this->foo()
, will look up from the context of Derived
.
When using a qualified-id, we explicitly state the context of where to look up a name. The expression Base::foo
states that we want to look up the name foo
from the context of Base
(it can find functions that Base
inherited, for example). Additionally, it disables virtual dispatch.
Therefore, d.Base::foo()
will find Base::foo
and call it; d.Base::bar()
will find Base::bar
and call it.
Fun fact: Pure virtual functions can have an implementation. They cannot be called via virtual dispatch, because they need to be overridden. However, you can still call their implementation (if they have one) by using a qualified-id.
#include <iostream>
struct Base {
virtual void foo() = 0;
};
void Base::foo() { std::cout << "look ma, I'm pure virtual!\n"; }
struct Derived : Base {
virtual void foo() { std::cout << "Derived::foo\n"; }
};
int main() {
Derived d;
d.foo(); // calls Derived::foo
d.Base::foo(); // calls Base::foo
}
Note that access-specifiers both of class members and base classes have an influence on whether or not you can use a qualified-id to call a base class's function on an object of a derived type.
For example:
#include <iostream>
struct Base {
public:
void public_fun() { std::cout << "Base::public_fun\n"; }
private:
void private_fun() { std::cout << "Base::private_fun\n"; }
};
struct Public_derived : public Base {
public:
void public_fun() { std::cout << "Public_derived::public_fun\n"; }
void private_fun() { std::cout << "Public_derived::private_fun\n"; }
};
struct Private_derived : private Base {
public:
void public_fun() { std::cout << "Private_derived::public_fun\n"; }
void private_fun() { std::cout << "Private_derived::private_fun\n"; }
};
int main() {
Public_derived p;
p.public_fun(); // allowed, calls Public_derived::public_fun
p.private_fun(); // allowed, calls Public_derived::public_fun
p.Base::public_fun(); // allowed, calls Base::public_fun
p.Base::private_fun(); // NOT allowed, tries to name Base::public_fun
Private_derived r;
r.Base::public_fun(); // NOT allowed, tries to call Base::public_fun
r.Base::private_fun(); // NOT allowed, tries to name Base::private_fun
}
Accessibility is orthogonal to name lookup. So name hiding does not have an influence on it (you can leave out public_fun
and private_fun
in the derived classes and get the same behaviour and errors for the qualified-id calls).
The error in p.Base::private_fun()
is different from the error in r.Base::public_fun()
by the way: The first one already fails to refer to the name Base::private_fun
(because it's a private name). The second one fails to convert r
from Private_derived&
to Base&
for the this
-pointer (essentially). This is why the second one works from within Private_derived
or a friend of Private_derived
.
Call derived class method from within base class?
Solution by OP.
public ref class BaseClass abstract
{
virtual void BaseClass::OverriddenMethod() abstract;
void BaseClass::Run()
{
// Do some initial work here.
// Call the derived class's version of OverridenMethod to do final work:
BaseClass::OverriddenMethod(); // DONT DO THIS!!!!!!!!
OverriddenMethod(); // DO THIS INSTEAD!!!!!
}
};
The issue here was because I was using a header for definitions and a cpp file for implementations of my base class. In the cpp file, I typically use ClassName::MemberName notation to refer to any of ClassName's members. However, doing so in this case forces the base class's virtual method to get called instead of the overridden method in the derived class.
This is why, when using the abstract keyword, I was getting the C3278 error when calling OverriddenMethod() inside of the Run() definition of the base class. Its because I was calling BaseClass::OverriddenMethod(), which points to nothing but an abstract definition.
C++: Calling base class method on derived class member
There are several options with different advantages and disadvantages.
- You can make the base class a template like this:
template<class Property>
class Base{
public:
Base(){};
void method(){property.speak();}
Property property;
};
class DerivedA : public Base<A>{
};
class DerivedB : public Base<B>{
};
It is clear and simple, but notice that DerivedA
and DerivedB
in this case have no common base class, so you can't, e.g. put pointers to them in the same container.
- You can use polymorphism.
class Base{
public:
virtual ~Base() {}
virtual void method() = 0;
};
class DerivedA : public Base{
public:
A property;
void method() override { property.speak(); }
};
class DerivedB : public Base{
public:
B property;
void method() override { property.speak(); }
};
This is a bit more complex, involves some code duplication and requires more resources (to store virtual table e.g.), but now the classes really have a common ancestor.
- Combine templates and polymorphism
class Base{
public:
virtual ~Base() {}
virtual void method() = 0;
};
template<class Property>
class Derived: public Base {
public:
Property property;
void method() override { property.speak(); }
};
using DerivedA = Derived<A>;
using DerivedB = Derived<B>;
This is actually option #2, but with no code duplication: we make the compiler generate code for us using templates.
- Other options. There may be other more specialized options depending on your requirements.
Is there a way to forbid a base class method call in the derived class?
This seems like a XY problem. Although I do not recommend this (I recommend rethinking the design) I found (for better or worse) a solution inspired from the CRTP pattern:
template <class D = void>
class Base
{
protected:
int data;
protected:
// This constructor should be called only in the derived classes
template <class Der = D, class = std::enable_if_t<std::is_base_of_v<Base, Der>>>
Base(int d): data(d) {}
public:
// This constructor can be called wherever except a derived classes!
template <class Der = D, class = std::enable_if_t<!std::is_base_of_v<Base, Der>>>
Base(): data(0) { }
};
class Derived : public Base<Derived>
{
int mydata = 1;
public:
// The developer must not forget to initialize "data"
Derived() : Base(24) {}
// I want to get a compilation error there
//Derived() : Base() {} // (1) compilation error here
};
auto test()
{
Base b1{};
//Base b2{24}; // (2) compilation error here
Derived d{};
}
Of course there are problems with this. For starters there is nothing stopping from creating a derived class as class Derived : public Base<void>
.
And if you want, you can add a common base class
class Base_l0
{
};
template <class D = void>
class Base_l1 : Base_l0
{
};
class Derived : public Base_l1<Derived>
{
};
Related Topics
String = String + Int: What's Behind the Scenes
How to Compare Two Rich Text Box Contents and Highlight the Characters That Are Changed
Import and Export Excel - What Is the Best Library
Why Is .Contains Slow? Most Efficient Way to Get Multiple Entities by Primary Key
Kill Process Tree Programmatically in C#
File I/O with Streams - Best Memory Buffer Size
Returning Only Part of Match from Regular Expression
Why Switch for Enum Accepts Implicit Conversion to 0 But No for Any Other Integer
Web API Put Request Generates an Http 405 Method Not Allowed Error
Understanding Async/Await in C#
How to Validate Azure Ad Security Token
Resharper Wpf Error: "Cannot Resolve Symbol "Myvariable" Due to Unknown Datacontext"
How to Assign a Func<> Conditionally Between Lambdas Using the Conditional Ternary Operator
This.Visible Is Not Working in Windows Forms