This question already has answers here:
If a private virtual function is overridden as a public function in the derived class, what are the problems?
(3 answers)
Overriding public virtual functions with private functions in C++
(7 answers)
Closed 4 years ago.
class A
{
public:
virtual void fun()
{
cout << "A Fun";
}
};
class B:public A
{
private:
void fun()
{
cout << "B Fun";
}
};
class C:public B{};
int main()
{
//Case1
A *ptr = new C();
ptr->fun();
/*
OUTPUT : B Fun
*/
//Case 2
B *ptr2 = new C();
ptr2->fun();
/*
ERROR:
main.cpp: In function ‘int main()’:
error: ‘virtual void B::fun()’ is private within this context
ptr2->fun();
^
note: declared private here
void fun()
^~~
*/
return 0;
}
In case 1 : I am able to call the private fun() in class B , but why I am not able to call the private fun() in case 2?
Why fun() in class B is having two different kind of behaviour?
I mean to say that when I make pointer of type A then fun() of class B act as public function but when I make pointer of type B then fun() of class B act as private function.
In case 1 : I am able to call the private fun() in class B [...]
No, you are not being able to call / are not calling a private method in a class B. You are calling a public method from class A that happens to be overriden in the child class.
This is especially useful when unit testing a private method. You simply make your class inherit from a dummy base class that declares the method of interest as public and (possibly pure) virtual.
Private-ness and public-ness is a purely compile time property of a member of a class/struct. The compiler checks if you have access to a member while compiling the code.
So in your code:
B b;
b.fun(); // Error! B::fun is private in this context!
A& a = static_cast<A&>(b); // `a` is a reference to `b`
a.fun(); // okay, A::fun is public.
// It just so happen that A::fun is virtual,
// So the function dispatched at runtime will be B::fun
// But the compiler has no mean to check this.
The behavior at runtime is determined if the function has been overridden, and only if the function A::fun is virtual. By overridding a virtual function, you must agree that expression using A will be dispatched to B, regardless what restrictions is on B. Code calling A::fun polymorphically must work with any subclasses, because code that deal with the base class cannot know the derived classes.
Related
Consider following code:
class A {
public:
virtual void f() const = 0;
void callf() const { f(); }
};
class B : public A {
virtual void f() const { }
};
int main()
{
B x;
x.callf();
return 0;
}
Class B derives from the abstract base class A, but "hides" the implemented method f() as private member.
Still, the inherited member callf() is able to call f(), which was public in the base class.
The code compiles with no warning on g++ 10.1.0 and clang++ 11.1.0.
Is this a legal code, i.e., does the inherited callf() correctly see the private member f()?
Alternatively, would it be possible for the derived class B to implement the purely virtual methods of the base class, such that they can only be called by B (and friends)?
Is this a legal code, i.e., does the inherited callf() correctly see the private member f()?
Yes, it is legal code. From the compiler's point-of-view, the callf function is referencing the f function of its own class; the fact that that is a virtual function does not affect the scope (or accessibility) – only the implementation, which will be in the form of a call to a v-table entry. That v-table entry will be correctly interpreted at run time, when it is called via the derived class.
I've read about virtual functions in C++ and understood how they provide the programmer with access to the member function of derived class using a pointer of base class. (aka Polymorphism).
The questions that have been bothering me are:
Why declare a function with a same name in the base class, if in the end it has to be declared virtual? (Note: I need answers with respect to the polymorphism aspect of virtual functions)
In the code below, if 'virtual display()' is called with a base class pointer (Line 22), it shows an error. Why are virtual functions in C++ so rigid w.r.t. not getting called by base class pointers?
.
#include <iostream>
using namespace std;
class B
{
public:
void virtual display()
{ cout<<"Inside base class.\n"; }
};
class D : public B
{
public:
void display()
{ cout<<"Inside derived class.\n"; }
};
int main()
{
B *b;
D d;
//Line-22 b->display(); Why can't 'b' call it's own display()?
b = &d;
b->display();
system("pause");
return 0;
}
Output:
Inside derived class.
b is a pointer not an object. Initially it didn't point to anything (so indirecting through it is an error); after b = &d, it points to a D object, so using it to call a virtual function will call D's override.
The virtual dispatch mechanism is defined so that the function is chosen based on the type of the actual object that the pointer points to, not the declared type of the pointer. So if it pointed to a B object then it would call B::display; here, it points to a D object, so it calls D::display.
Why declare a function with a same name in the base class, if in the end it has to be declared virtual?
It needs to be declared in the base class so that, when using a pointer to the base class, the compiler knows that it exists. Whether calling the function through the pointer will call the base-class version, or a version overridden by a derived class, depends on the type of the object.
In the code below, if virtual display() is called with a base class pointer (Line 22), it shows an error.
That's because it doesn't point to anything, so using it is an error. If it were to point to a B object, then it would call the function declared in B.
B b_obj;
b = &b_obj;
b->display(); // "Inside base class"
Why are virtual functions in C++ so rigid w.r.t. not getting called by base class pointers?
They're not; that's the usual way of calling them. But the pointer must point to a valid object for virtual dispatch to work.
I confess I don't quite understand your question #1. Declaring a virtual function in a base class allows derived classes to override that implementation.
There are tons of uses for this (just search for polymorphism, Liskov substitution etc.). As a simple (and contrived) example, consider this:
struct File
{
virtual void open() { some_code; }
virtual void close() { some_code; }
static std::unique_ptr<File> create();
};
struct DbgFile : File
{
virtual void open() { std::clog << "Opening"; File::open(); }
virtual void open() { std::clog << "Closing"; File::close(); }
};
std::unique_ptr<File> File::create()
{
#ifdef NDEBUG
return { new File };
#else
return { new DbgFile };
#endif
}
int main()
{
auto f = File::create();
f->open();
f->close();
}
The above main() uses the File interface, but in debug builds, it will actually work with an object of type DbgFile which logs all operations happening on it.
As to your question #2, the problem in your code is that b doesn't point anywhere. If you do this instead, it will work just fine:
int main()
{
B *b;
B bb;
D d;
b = &bb;
b->display(); // Outputs "Inside base class."
b = &d;
b->display(); // Outputs "Inside derived class."
// In addition, you can explicitly suppress dynamic dispatch:
b->B::display(); // Outputs "Inside base class."
return 0;
}
Why declare a function with a same name in the base class, if in the end it has to be declared virtual? (Note: I need answers with respect to the polymorphism aspect of virtual functions)
It's necessary because,base class has to know which function definition it needs to call at runtime. Its a kind of interface.
In the code below, if 'virtual display()' is called with a base class pointer (Line 22), it shows an error. Why are virtual functions in C++ so rigid w.r.t. not getting called by base class pointers?
Since the pointer is not initialized its throwing an error. Use like below.
Base baseObj1,*basePtr;
basePtr= &baseObj1;
basePtr->Display(); //Inside base class
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Public virtual function derived private in C++
class B
{
private:
int b;
public:
B(int i);
virtual void show()
{
cout<<"B::show()called. "<<b<<endl;
}
};
B::B(int i=0)
{
b=i;
}
class D:public B
{
private:
int d;
void show()
{
cout<<"D::show() called. "<<d<<endl;
}
public:
D(int i, int j);
};
D::D(int i=0, int j=0):B(i)
{
d=j;
}
void fun(B&obj)
{
obj.show();
}
/*if I redefine fun() as follow, the result would be the same
void fun(B*obj)
{
obj->show();
}
*/
int main()
{
D *pd=new D(5,8);
fun(*pd); //K
delete pd;
}
The output of the program is "D::show() called.", which means the virtual function declared in the private part of class D is invoked. Don't you think it weird? How could a private member of a class be accessed from outside?
The crucial part is that your function void fun(B&obj) takes an argument of static type B& (so a conversion happens at the call site; the same happens with B*).
Since B::show is public, your code has no problem calling it. When the compiler looks at how to dispatch the call it sees that show is virtual so it calls D::show. The fact that you could not have called D::show if obj was of type D is irrelevant.
Unlike Java, in C++ the access specifier doesn't affect the virtual functions.
'Access specifier' is a compile time check which is made on the class method with respect to static type of the handle. e.g. in your code obj is of type B and B::show() is public; hence the code is legal.
obj may refer dynamically to some other type than B.
Remember that virtual function dispatch is a runtime phenomena. (In Java it would have given a runtime error.)
B::show() is public and once it's invoked, the virtual functionality will kick in and call the appropriate object's function.
If you try calling D::show() directly then you will get the expected compiler error.
It's not weird. In B, the method is public. You can call show() on a B object.
It's just that the method gets dispatched to an extending class.
I believe, a derived class can override only those functions which it inherited from the base class. Is my understanding correct.?
That is if base class has a public member function say, func, then the derived class can override the member function func.
But if the base class has a private member function say, foo, then the derived class cannot override the member function foo.
Am i right?
Edit
I have come up with a code sample after studying the answers given by SO members. I am mentioning the points which i studied as comments in the code. Hope i am right. Thanks
/* Points to ponder:
1. Irrespective of the access specifier, the member functions can be override in base class.
But we cannot directly access the overriden function. It has to be invoked using a public
member function of base class.
2. A base class pointer holding the derived class obj's address can access only those members which
the derived class inherited from the base class. */
#include <iostream>
using namespace std;
class base
{
private:
virtual void do_op()
{
cout << "This is do_op() in base which is pvt\n";
}
public:
void op()
{
do_op();
}
};
class derived: public base
{
public:
void do_op()
{
cout << "This is do_op() in derived class\n";
}
};
int main()
{
base *bptr;
derived d;
bptr = &d;
bptr->op(); /* Invoking the overriden do_op() of derived class through the public
function op() of base class */
//bptr->do_op(); /* Error. bptr trying to access a member function which derived class
did not inherit from base class */
return 0;
}
You can override functions regardless of access specifiers. That's also the heart of the non-virtual interface idiom. The only requirement is of course that they are virtual.
But if the base class has a private member function say, foo, then the derived class cannot override the member function foo.
In Java, you can't. In C++, you can.
You are correct in that to override a function in a derived class, it must inherit it from the base class (in addition, the base class function must be virtual). However you are wrong about your assumption that virtual functions are not inherited. For example, the following works well (and is actually a known idiom for precondition/postcondition checking):
class Base
{
public:
void operate_on(some thing);
private:
virtual void do_operate_on(some thing) = 0;
};
void Base::operate_on(some thing)
{
// check preconditions
do_operate_on(thing);
// check postconditions
}
class Derived: public Base
{
// this overrides Base::do_operate_on
void do_operate_on(some thing);
};
void Derived::do_operate_on(some thing)
{
// do something
}
int main()
{
some thing;
Base* p = new Derived;
// this calls Base::operate_on, which in turn calls the overridden
// Derived::do_operate_on, not Base::do_operate_on (which doesn't have an
// implementation anyway)
p->operate_on(thing);
delete p;
}
A way to see that private methods are really inherited is to look at the error messages generated by the following code:
class Base
{
private:
void private_method_of_B();
};
class Derived:
public Base
{
};
int main()
{
Derived d;
d.private_method_of_B();
d.method_that_does_not_exist();
}
Trying to compile this with g++ leads tot he following error messages:
privatemethodinheritance.cc: In function 'int main()':
privatemethodinheritance.cc:4: error: 'void Base::private_method_of_B()' is private
privatemethodinheritance.cc:15: error: within this context
privatemethodinheritance.cc:16: error: 'class Derived' has no member named 'method_that_does_not_exist'
If class Derived wouldn't inherit that function, the error message would be the same in both cases.
No You can not over ride any function in base class .
My reason for this notion is that if you define the function in derived class that has the same function signiture in base class , the base class function will become hidden for derived class .
For more information about this exciting issue just visit :
http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8a.doc%2Flanguage%2Fref%2Foverload_member_fn_base_derived.htm
It's also depends on the type of inheritance
class Derived : [public | protected | private] Base { };
In order to override a function inherited from base class, it should be both virtual, and classified as public or protected.
This question already has answers here:
Closed 12 years ago.
Possible Duplicates:
C++ : implications of making a method virtual
Why is 'virtual' optional for overridden methods in derived classes?
I wonder, what is documented behavior in the following case:
You have
class A
{
virtual void A()
{
cout << "Virtual A"<<endl;
}
void test_A()
{
A();
}
}
class B: public A
{
void A()
{
cout << "Non-virtual A in derived class"<<endl;
}
void test_B()
{
A();
}
}
A a; B b;
a.test_A();
b.test_A();
b.test_B();
What it supposed to do according to C++ standard and why?
GCC works like B::A is also also virtual.
What shoudl happen in general when you override virtual method by non-virtual one in derived class?
The sub-class member function is implicitly virtual if a virtual base-class member function with the same name and signature exists.
The code should not compile as you cannot name a method with the name of the class. But regarding what I understand that is your real question:
Will making a method virtual imply that the same method in all the derived classes is virtual even if the virtual keyword is not present?
The answer is yes. Once a method is declared virtual in a class, then all overrides of that method will be virtual, and the virtual keyword is optional in derived classes (even if I recommend typing it, if only for documentation purposes). Note that for a method in a derived class to be an override it has to have the same name and signature, with only potential difference being a covariant return type:
struct A {};
struct B : A {};
struct base {
virtual A* foo();
virtual A* bar();
};
struct derived : base {
virtual B* foo(); // override, covariant return type
virtual int bar(); // not override, return type is not covariant
virtual A* bar(int); // not override, different argument list
};
This code is ill-formed. A constructor cannot have a return type (as you have done for the constructor of 'A'). Also a constructor cannot be virtual.
After fixing A's constructor, class B is ill-formed as the constructor of A is private.
So, there are many problems with this code (including missing semicolons at the class definitions).
According to standard it should be
A a; B b;
a.test_A(); //"Virtual A"
b.test_A(); //Non-virtual A in derived class
b.test_B(); //Non-virtual A in derived class