#include <iostream>
using namespace std;
class Base1 {
public:
virtual void f(int n) = 0;
};
class Base2 {
public:
virtual void f(char *s) = 0;
};
class Derive1 : public Base1, public Base2 {
public:
void f(int n) { cout << "d1 fn" << endl; }
void f(char *s) { cout << "d1 fs" << endl; }
};
class Derive2 : public Derive1 {
public:
void f(int n) { cout << "d2 fn" << endl; }
void f(char *s) { cout << "d2 fs" << endl; }
};
int main() {
Derive1 *d1 = new Derive2();
int n = 0;
char *s = "";
d1->f(n);
d1->f(s);
return 0;
}
The above code runs as expected, but if I comment out one method of Derive1, I got conversion error; if I comment out both methods of Derive1, I got methods ambiguity error.
What confused me is that why Derive1 has to define these two methods, why defining them only in Derive2 is not working. I need some help to understand this.
Some clarifications:
Let's suppose I never want to create any instances of Derive1. So, it is totally okay if Derive1 is an abstract class.
"All pure virtual functions should have a definition in derived class." This is not true if I don't want to create instances of this derived class.
If I change f in Base1 to f1, and f in Base2 to f2(just change names), then Derive1 does not need to define any of them, just defining f1 and f2 in Derive2 works.
So, with the support of method overloading, I thought, in the above code, I declared a function with the name like f_int in Base1; in Base2 I declared a function with the name like f_str. This is the way how the compiler implements method overloading, right? But it seems like this is not the case.
Derive1 is a derived class from Base1 and Base2. Derived classes must implement all pure virtual functions of their base classes.
It doesn't help Derive1 that Derive2 implements these functions, because it is possible to instantiate a Derive1, and to do so it must implement all inherited pure virtual methods.
For example, if you did not implement the functions in Derive1, what would you expect the behavior of this to be?
Derive1* d1 = new Derive1;
int n = 0;
char *s = "";
d1->f(n);
d1->f(s);
Derive1 didn't implement these, and d1 isn't a Derive2 instance, so what is it supposed to do?
If you declare a pure virtual function in a class, it will turned to become an abstract class and you can't instantiate that one. And all pure virtual functions should have a definition in derived class. Your both base classes has pure virtual functions and so your derived1 should define the pure virtual functions of base classes.
Let's start with removing both in Derived1:
When you call d1->f, you haven't created any specific to that class, so it looks to its base classes. Each base class would be treated as a separate set of candidates. So first it checks base1 and see an f, then checks base2 and sees another f. The compiler can't pick which one to call, so the call is ambiguous. You can using the parent functions into Derived1 if you don't want to re-implement them, or give the compiler a hint about which base to use.
If you only comment out one of the functions in Derived1, the one you you leave hides both parent versions, preventing either one of them from being selected. At this point you can call the one you've defined and cannot call the other one, unless you again tell the compiler which specific base class you want to call it from.
Related
I got a Question in my Exam which was this:
Function Overriding means the functions have the same prototype but
differ in their body
Justify the Statement with the help of an Example.
Now I quoted this code snippet as Example :
#include<iostream>
using namespace std;
class A {
public: virtual void print() {
cout << "I am Base Class's print Function" << endl;
}
};
class B: public A {
public: void print() {
cout << "I am Derived's Class print function" << endl;
}
};
Here I have made two classes, Class A and Class B and Class B is inheriting Class A. Now, by definition of Method Overriding, we mean that the Function which gets created in the Base Class gets overridden in the Derived Class.
I made the Function in the Base Class as a Virtual Function.
Now, my main() file:
int main() {
A * a1;
B b1;
a1 = & b1;
a1 - > print();
}
Now, I want to ask that is my above code snippet example for above question is right or not. I have performed Function Overriding at run time. In my main file, the Base Class Object is a Pointer that is having the Address of the Derived Class. When I will call print() function using a1, it will execute the print() function of the Derived Class.
So isn't my example justified? Am I right or not?
You could use the classical Cat vs Dog example where both classes inherit from a common base class, i.e. Animal. The common base class can then have a pure virtual function that is then overridden with a differing implementation (method body) in each subclass.
#include <iostream>
class Animal
{
public:
virtual ~Animal() = default;
virtual void MakeSound() const = 0;
};
class Dog : public Animal
{
public:
virtual void MakeSound() const override;
};
class Cat : public Animal
{
public:
virtual void MakeSound() const override;
};
void Dog::MakeSound() const
{
std::cout << "Woof!" << std::endl;
}
void Cat::MakeSound() const
{
std::cout << "Meow!" << std::endl;
}
int main()
{
const Dog dog{};
const Cat cat{};
const Animal& firstAnimal{dog};
const Animal& secondAnimal{cat};
/*
* These functions have the same prototype, void MakeSound(),
* but differ in their implementation.
*/
firstAnimal.MakeSound();
secondAnimal.MakeSound();
return 0;
}
If you teacher expected this as answer and considers your example as wrong then I would argue that they teach you overriding the wrong way.
From cppreference:
Virtual functions are member functions whose behavior can be overridden in derived classes.
Of course this does not strictly imply the reverse statement: "functions that can be overriden are virtual". But if this wasnt true, the quoted sentence would make little sense.
Non-virtual methods are not really meant to be overriden. From the C++ FAQ:
Should a derived class redefine (“override”) a member function that is non-virtual in a base class?
It’s legal, but it ain’t moral. [...]
Note that they put "override" in quotes, because strictly speaking it is not overriding but merely redefining.
Further, you can read on cpprefernce about the override specifier (emphasize mine):
In a member function declaration or definition, override ensures that the function is virtual and is overriding a virtual function from a base class. The program is ill-formed (a compile-time error is generated) if this is not true.
TL;DR If I had to judge I would consider this as a misleading bad example for overriding, while your code seems fine. It could benefit from using override and A should have a virtual destructor, but thats details.
Considering this code example:
#include <iostream>
using namespace std;
class Base
{
private:
int number;
public:
Base():number(10){}
~Base(){}
virtual void print()
{
cout << "Base class" << endl;
}
};
class Derived : public Base
{
public:
Derived():Base(){}
~Derived(){}
void print(int value)
{
//printing number in Base class and paramter value
cout << "Derived with value " << value << " number is" << number << endl;
}
};
I wanted to use polymorphism and call theoverloaded print() function.
So use these classes as follows:
void somewhere_else()
{
Base* polymorphism = new Derived();
polymorphism->print(5); //Error indicating there are too many parameter
//thinking that I am trying to use print in Base class
((Derived*)polymorphism)->print(5)
//This works as I am casting the variable as Derived variable
}
Unfortunately, I can't call print() from the base class pointer (compilation error, see comment above). I can only call it with a cast.
Is there a better way to keep the polymorphism and still calls overloaded function based on derived class?
In your code you have two different member functions, that have different signatures:
a virtual print() that takes no argument. It is declared and defined in Base, and inherited in Derived
a non-virtual print() that takes one int argument. It is declared and defined ONLY for Derived
So the base object doesn't know a print function with an int parameter. This is why you need to cast (which is by the way a symptom that should ring alarm bells if you need it).
How to improve ?
First, if you want to override a virtual function in a derived class, use the keyword override:
class Derived : public Base
{
public:
Derived():Base(){}
~Derived(){}
void print(int value) override
{
...
}
};
This will ensure an error message in case of subtle mismatch in the function signature:
prog.cpp:23:10: error: ‘void Derived::print(int)’ marked ‘override’, but does not override
void print(int value) override
^~~~~
Then make sure that the signatures are aligned in the base class and derived class (i.e. either both take an int argument or non of them.
Note that you can't access a private member of the base class in a derived class. You have to define number as protected to print it in Derived.
Finally, if you have a base class having a virtual member, it is a sound practice to systematically make the destructor virtual. This will avoid subtle bugs for more complex classes:
class Base
{
protected:
int number;
public:
Base():number(10){}
virtual ~Base(){}
virtual void print(int value)
{
...
}
};
Here the online demo
Now that the things are working, here a short article making the difference between overload and override.
Is it sufficient to define the method once to be virtual in the inheritance hierarchy to make polymorphism to work.
In the following example Der::f is not defined to be virtual but d2->f(); prints der2
I am using VS IDE (may be it is only there...)
class Base
{
public:
virtual void f() { std::cout << "base"; }
};
class Der : public Base
{
public:
void f() { std::cout << "der"; } //should be virtual?
};
class Der2 : public Der
{
public:
void f() { std::cout << "der2"; }
};
int main()
{
Der* d2 = new Der2();
d2->f();
}
Yes, polymorphism will work if you define method as a virtual only in your Base class. However, it is a convention I came across working with some large projects to always repeat virtual keyword in method declarations in derived classes. It may be useful when you are working with a lot of files with complex class hierarchy (many inheritance levels), where classes are declared in separate files. That way you don't have to check which method is virtual by looking for base class declaration while adding another derived class.
Everything that inherits from Base - directly or through several layers will have f() virtual as if the class declarion had explicitely placed virtual when f() was declared.
Yesterday, I wrote some code and i would really appreciate a judgement if this is good or bad practice. And if its bad, what could go wrong.
The construct is as followed:
The base class A comes from an API sadly as a template. The goal was to be able to put derived classes from A in a std::vector. I achieved this with the base class B from which all derived classes that inherit from A will inherit. Without the pure-virtual function in B the foo() function from A was called.
With the pure-virtual function in B the foo() version from C get called. This is exactly what I want.
So is this bad practice?
EDIT:
To clear some misunderstandings in my example code out:
template <class T>
class A
{
public:
/* ctor & dtor & ... */
T& getDerived() { return *static_cast<T*>(this); }
void bar()
{
getDerived().foo(); // say whatever derived class T will say
foo(); // say chicken
}
void foo() { std::cout << "and chicken" << std::endl; }
};
class B : public A<B>
{
public:
/* ctor & dtor */
virtual void foo() = 0; // pure-virtual
};
class C : public B
{
public:
/* ctor & dtor */
virtual void foo() { std::cout << "cow"; }
};
class D : public B
{
public:
/* ctor & dtor */
virtual void foo() { std::cout << "bull"; }
};
The std::vector shall contain both, C as well as D and
void main()
{
std::vector<B*> _cows;
_cows.push_back((B*)new C()));
_cows.push_back((B*)new D()));
for(std::vector<B*>::size_type i = 0; i != _cows.size(); ++i)
_cows[i].bar();
}
with output
cow and chicken
bull and chicken
is desired.
As far as I know is there no other way to store classes derived from a template class in a container than the use of a base class. If I use a base class for my derived classes, e.g., B i must cast every instance within the vector back to its proper class. But at the time bar() is called, I don't know the exact type.
I call it bad practice for doing possibly confusing and obfuscating things.
1) A function name should in all base and sub-classes either be virtual or non-virtual.
mixing overriding and overloading within the inheritance hierachry is a very bad idea.
No one really expects something like that.
Thus if A::foo should be virtual as well, or B and C foo should not.
2) Preferably base classes should be interfaces.
As such A:foo should be pure virtual and not B::foo.
2b) If a base class has already provided a default implementation don't declare the function pure virtual in a sub-class.
I am trying to understand why the following code does not compile, apparently the solution relies in specifically declaring the dependency on method_A in the derived class.
Please refer to the following code:
class Base
{
public:
void method_A(int param, int param2)
{
std::cout << "Base call A" << std::endl;
}
};
//does not compile
class Derived : public Base
{
public:
void method_A(int param)
{
std::cout << "Derived call A" << std::endl;
}
};
//compiles
class Derived2 : public Base
{
public:
using Base::method_A; //compile
void method_A(int param)
{
std::cout << "Derived call A" << std::endl;
}
};
int main ()
{
Derived myDerived;
myDerived.method_A(1);
myDerived.method_A(1,2);
Derived2 myDerived2;
myDerived2.method_A(1);
myDerived2.method_A(1,2);
return 0;
}
"test.cpp", (S) The wrong number of arguments have been specified for "Derived::method_A(int)".
What is the technical reason that prevents the derived class to know its base class is implementing the method it's trying to overload?
I am looking in understanding better how the compiler/linker behaves in this case.
Its called Name Hiding. When you define a non virtual method with the same name as Base method it hides the Base class method in Derived class so you are getting the error for
myDerived.method_A(1,2);
To avoid hiding of Base class methods in Derived class use using keyword as you did in Derived2 class.
Also if you want to make it work you can do it explictly
myDerived.Base::method_A(1,2);
Check out this for better explanation why name hiding came into picture.
Well, for one you're calling
myDerived.method_A(1,2);
with 2 arguments, whereas both in base and derived the method is declared to take only one argument.
Secodnly, you're not overriding anything, because method_A is not virtual. You're overloading.
If your intention is to override void Base::method_A(int param, int param2) then you should mark it virtual in the base class:
virtual void method_A(int param, int param2)
Any function overriding this must have the same parameters and almost the same return type ('almost' loosely meaning that the differing return types must be polymorphically related, but in most cases it should have the identical return type).
All you're currently doing is overloading the function in the base class. The using keyword is bringing the base class function into the child class' namespace, as the language behaviour is not to do this by default.