C++: Method overloading when inheritance and "using" are involved - c++

Say there are two classes: Base and Derived. The code is listed below. My question is, how does the program know d.print() (tagged with A in code) is meant to call Derived::print() instead of Base::print()?
Please note that I deliberately added using Base::print; to confuse the compiler. These two print() methods have the same signature (am I right?) and are not hiding each other because of the using statement.
#include <iostream>
using namespace std;
class Base {
public:
void print() { cout << "print() of Base is called\n"; }
};
class Derived : public Base {
public:
void print() { cout << "print() of Derived is called\n"; }
using Base::print; // I delibarately added this line
};
int main() {
Derived d;
d.print(); // A
Base *pBase = (Base *)&d;
pBase->print(); // B
}
The result is
print() of Derived is called
print() of Base is called
Edit: the accepted answer gave a quote. For readers' convenience I paste the (nearly) whole quoted paragraph here, split in sentence:
Using-declaration introduces a member of a base class into the derived class definition, such as to expose a protected member of base as public member of derived.. (that's what I expected)
If the name is the name of an overloaded member function of the base class, all base class member functions with that name are introduced. (that's what I expected, too)
If the derived class already has a member with the same name, parameter list, and qualifications, the derived class member hides or overrides (doesn't conflict with) the member that is introduced from the base class. (solved my problem)

The explicitly introduced using does not hide the method you have in the derived class because of this rule (from the cppreference documentation for using)
If the derived class already has a member with the same name, parameter list, and qualifications, the derived class member hides or overrides (doesn't conflict with) the member that is introduced from the base class.
The compiler is not confused, it's doing the right thing. The using is not hiding the print() method in the derived class because it defines a print() method.
When you call print() with a Base pointer, print() is not virtual the base pointer can only call the method that is registered with the static type of the thing it is pointing to, i.e. Base::print()

Related

Overriding of const member function in C++

Consider the following code:
#include <iostream>
#include<string>
using namespace std;
class Base
{
public:
virtual string print() const
{
return "This is Base class";
}
};
class Derived : public Base
{
public:
virtual string print() const
{
return "This is Derived class";
}
};
void describe(Base p)
{
cout << p.print() << endl;
}
int main()
{
Base b;
Derived d;
describe(b);
describe(d);
return 0;
}
On executing this code, it gives the output as
This is Base class
This is Base class
I had couple of doubts in this program:
The function print in class Base is a const member function, hence after inheritance, when we try to override the definition of print in Derived class, why doesn't the compiler give an error.
In this program, how we can we pass a derived class object (d) to the function which expects an argument of data Type Base.
Even if we could somehow pass the derived class object to the function, why does it print "This is Base class" instead of "This is Derived Class".
Does implicit type-conversion take place when I pass a derived class object to function describe?
I had be grateful if someone could explain me the working of this code.
The function print in class Base is a const member function, hence after inheritance, when we try to override the definition of print in Derived class, why doesn't the compiler give an error.
There is no error because the program is well-formed. It is unclear why you bring up the detail that the member function is const. Constness of a member function has no effect on whether the function can be overridden. Did you assume that const means final?
In this program, how we can we pass a derived class object (d) to the function which expects an argument of data Type Base.
Because that class Base is a public base of the Derived class, and thus the derived object is implicitly convertible to the base. The result of the conversion is a copy of the base class sub object. This is colloquially called "slicing".
Even if we could somehow pass the derived class object to the function, why does it print "This is Base class" instead of "This is Derived Class".
Because there is no derived class object inside the function. There is a copy of the base.
Does implicit type-conversion take place when I pass a derived class object to function describe?
Yes. When you pass an argument of a type that is different from the type of a non-reference parameter, there is always an implicit conversion.
Indirection is necessary for runtime polymorphism. Try the same using a reference to base as parameter and you'll see the overriding function called.
Your first question is why it did not give you an error because your function is const. Const function does not prohibit you from overriding it. If you want your function to be not overridden by derived classes you can declare that function final.
virtual string print() const final;
Now this will not be overridable by any other derived class. As far as you are concerned about the const. You can Overload your function on the basis of constness. For example, you can have.
virtual string print() const; // Does not modify anything
virtual string print(); Can modify `this`
For the second question can pass the Derived class object to a function witch expect the Base class object. But It is only possible if it is via reference or via a pointer.
void describe(const Base& p);
void describe(Base* p);
For the third question as you passed via copy, so your derived class object is narrowed to Base class. Which essentially loss all the additional information other than its Base class.
The fourth question has the same answer as 3.
This is fully functional code as you had expected to run.
#include <iostream>
#include<string>
using namespace std;
class Base
{
public:
virtual string print() const
{
return "This is Base class";
}
};
class Derived : public Base
{
public:
virtual string print() const override
{
return "This is Derived class";
}
};
void describe(const Base& p)
{
cout << p.print() << endl;
}
int main()
{
Base b;
Derived d;
describe(b);
describe(d);
return 0;
}
Here you can see I declared overridden function override to tell the compiler that this function is being overridden from its Base Class. Without this, it works as expected but it's like function hiding rather than overriding.

Why C++ does not support overloading across scopes?

I believe that the best answer is already given here : Why does an overridden function in the derived class hide other overloads of the base class?
But I am confused a little bit, specially with the statement :
In order to override this behavior, an explicit action is required from the user: originally a redeclaration of inherited method(s) (currently deprecated), now an explicit use of using-declaration.
Suppose I have the following program :
#include <iostream>
using namespace std;
class Base
{
public:
int f(int i)
{
cout << "f(int): ";
return i+3;
}
};
class Derived : public Base
{
public:
double f(double d)
{
cout << "f(double): ";
return d+3.3;
}
};
int main()
{
Derived* dp = new Derived;
cout << dp->f(3) << '\n';
cout << dp->f(3.3) << '\n';
delete dp;
return 0;
}
I have two questions :
Can I assume, w.r.t derived class object, the int f(int i) function does not exist at all. This is not inherited because of name hiding.
If I have to use this function in Derived class, I have to define it again in derived class?
Can I assume, w.r.t derived class object, the int f(int i) function does not exist at all. This is not inherited because of name hiding.
It is inherited, it's just ... hidden, can't be found if you don't specify the scope (unqualified name lookup. You can specify it explicitly with scope resolution operator :: (qualified name lookup) :
dp->Base::f(3);
If I have to use this function in Derived class, I have to define it again in derived class?
As the quoted answer said, you can do it with "an explicit use of using-declaration".
class Derived : public Base
{
public:
using Base::f;
...
};
EDIT (for supplemental questions from comment)
If it's name hidden, that means I can declare it again ? Same name, same parameters?
Yes, you can. It's still name hiding.
If yes, what if I also added using Base::f along with the new declaration? Will it result in double definition?
No, it's not double definition. Using declaration just introduces the name into the derived class scope. And the member function declared in derived class will hide the one introduced from base class, it's still name hiding. (Note you still could call the one of base class by dp->Base::f(3);.)
If the derived class already has a member with the same name, parameter list, and qualifications, the derived class member hides or overrides (doesn't conflict with) the member that is introduced from the base class.

why name publicizing is there when we want to inherit the base class privately?

Generally, we wish to use private inheritance to hide the implementation details to the base class. If this is true,
1) Why is the name publicizing feature is there again ? Is it only for language completeness or is there any practical usage also?
2) Even though I publicize the base class function name, a derived class can still declare another function with same name. Please consider the following code.
#include "iostream"
using namespace std;
class Base {
public:
int zoo;
Base() {zoo =5;}
int sleep() const {return 3;}
};
class Derived : Base { // Private inheritance
public:
using Base::zoo;
using Base::sleep;
int sleep() const { return 4.0; }
};
int main() {
Derived der;
der.sleep();
cout<<" zoo is : "<<der.zoo<<endl;
cout<<" Sleep is : "<<der.sleep()<<endl;
}
In the above snippet, even though we publicize the name, we can still declare the name in derived class, and we can access the base class version of member variables. How the memory is managed?
Thank you.
http://en.cppreference.com/w/cpp/language/using_declaration
If the derived class already has a member with the same name, parameter list, and qualifications, the derived class member hides or overrides (doesn't conflict with) the member that is introduced from the base class.
That link has specific examples of exactly what you are doing an re-iterates what I quoted above and how the base member is simply hidden by the derived member.

why I changed parent virtual function arguments in child hides the father function c++?

I made a class with virtual function f() then in the derived class I rewrote it like the following f(int) why can't I access the base class function throw the child instance ?
class B{
public:
B(){cout<<"B const, ";}
virtual void vf2(){cout<<"b.Vf2, ";}
};
class C:public B{
public:
C(){cout<<"C const, ";}
void vf2(int){cout<<"c.Vf2, ";}
};
int main()
{
C c;
c.vf2();//error should be vf2(2)
}
You have to do using B::vf2 so that the function is considered during name lookup. Otherwise as soon as the compiler finds a function name that matches while traversing the inheritance tree from child -> parent -> grand parent etc etc., the traversal stops.
class C:public B{
public:
using B::vf2;
C(){cout<<"C const, ";}
void vf2(int){cout<<"c.Vf2, ";}
};
You are encountering name hiding. Here is an explanation of why it happens ?
In C++, a derived class hides any base class member of the same name. You can still access the base class member by explicitly qualifying it though:
int main()
{
C c;
c.B::vf2();
}
You were caught by name hiding.
Name hiding creeps up everywhere in C++:
int a = 0
int main(int argc, char* argv[]) {
std::string a;
for (int i = 0; i != argc; ++i) {
a += argc[i]; // okay, refers to std::string a; not int a;
a += " ";
}
}
And it also appears with Base and Derived classes.
The idea behind name hiding is robustness in the face of changes. If this didn't exist, in this particular case, then consider what would happen to:
class Base {
};
class Derived: public Base {
public:
void foo(int i) {
std::cout << i << "\n";
}
};
int main() {
Derived d;
d.foo(1.0);
}
If I were to add a foo overload to Base that were a better match (ie, taking a double directly):
void Base::foo(double i) {
sleep(i);
}
Now, instead of printing 1, this program would sleep for 1 second!
This would be crazy right ? It would mean that anytime you wish to extend a base class, you need to look at all the derived classes and make sure you don't accidentally steal some method calls from them!!
To be able to extend a base class without ruining the derived classes, name hiding comes into play.
The using directive allows you to import the methods you truly need in your derived class and the rest are safely ignored. This is a white-listing approach.
When you overload a member function in a base class with a version in the derived class the base class function is hidden. That is, you need to either explicitly qualify calls to the base class function or you need a using declaration to make the base class function visible via objects of the derived class:
struct base {
void foo();
void bar();
};
struct derived: base {
void foo(int);
using base::foo;
void bar(int);
};
int main() {
derived().foo(); // OK: using declaration was used
derived().bar(); // ERROR: the base class version is hidden
derived().base::bar(); // OK: ... but can be accessed if explicitly requested
}
The reason this is done is that it was considered confusing and/or dangerous when a member function is declared by a derived function but a potenially better match is selected from a base class (obviously, this only really applies to member functions with the same number of arguments). There is also a pitfall when the base class used to not have a certain member function: you don't want you program to suddenly call a different member function just because a member function is being added to the base class.
The main annoyance with hiding member functions from bases is when there is a set of public virtual functions and you only want to override one of them in a derived class. Although just adding the override doesn't change the interface using a pointer or a reference to the base class, the derived class can possibly not used in a natural way. The conventional work-around for this to have public, non-virtual overload which dispatch to protected virtual functions. The virtual member function in the various facets in the C++ standard library are an example of this technique.

Redifinition of functions in derived class

In C++ primer plus it is written that
"If you redefine just one version of function in derived class, the other functions of base class become hidden and cannot be used by objects of the derived class."
Then why does this code call fun1() ,as it should be hidden for the derived class object i.e. obj.
#include<iostream>
using namespace std;
class base
{
public:
void fun1()
{
cout<<"base"<<endl;
}
void fun2(int a)
{
cout<<"function2";
}
};
class derived :public base
{
public:
void fun2()
{
cout<<"fun2";
}
};
int main()
{
derived obj;
obj.fun1();
}
When it says "the other functions of the base class become hidden" it actually means "the base class functions with the same name become hidden in the derived class".
So, if you declare two overloaded versions of fun1 in the base class (say, fun1(void) and fun1(int)), and then declare another version of fun1 in the derived class (say, fun1(double)), the function in the derived class will hide both fun1 functions inherited from the base class.
In your example, the derived fun2 hides the base fun2, but it doesn't hide base fun1. This is why you can successfully call fun1 in your example.
You can observe the fact that derived fun2 has hidden the base fun2 by trying to call
obj.fun2(42);
Since the fun2(int) from the base class is hidden by fun2(void) from the derived class, the call will fail to compile.
In the above example you have not redefined fun1, but redefined fun2. so if you call fun1 it would still call the base class function. but if you call obj.fun2() it will class derived class function.
You haven't redefined any version of fun1; you have only overloaded fun2. This doesn't hide everything in the base class; it hides the other overloads of the same function.
if you want a function in a derived class do something different to the parent class then you need to make the parent function virtual.
virtual void fun1() { ... }