Say class B derives from class A. That both declare f(). f is protected. Hence f will only be called inside A and inside B. Does f() need to be declared virtual?
Or rather: say C derives from B derives from A. B and A declare protected non-virtual f(). Will a call to f() in C and B resolve to B::f() and in A to A::f()?
In that case, should we always avoid virtual for protected members to have static resolution? Is this done automatically? Thanks!
As long as the call to f() is done in a function derived from A (and not overloaded/reimplemented in B or C), the this pointer resolves to A* and therefore A::f() is called. So no, you still need a virtual function in this case.
Declaring your protected method virtual is necessary when you want polymorphic behaviour (an example to this is the Template Method pattern), and is to be avoided when you don't. However, in the latter case you should not shadow the function with another function having the same signature in the subclass, otherwise you get puzzling behaviour (like the one you describe in your 2nd paragraph) which opens up the possibility for subtle bugs.
I am a bit rusty on my C++ but I would say that "static resolution" would only be guaranteed when you declare the method private and thus you need virtual together with protected in your scenario...
So:
class A {
public:
void f() { std::cout << "A::f\n"; }
};
class B : public A {
public:
void f() { std::cout << "B::f\n"; }
};
As long as the compiler knows that an object is actually a B, it will call f() in B. But, this is not always the case:
void callF(A* a)
{
a->f();
}
B b;
callF(&b); // prints A::f
If you want functions like callF to call the correct f() function, make it virtual. Generally, you make functions virtual if it makes sense to override them in a descendant class. This is often the case for protected functions.
Related
I am just confused about the tiny program on inheritance below:
#include<iostream>
using namespace std;
struct B {
virtual int f() { return 1; }
}; // f is public in B
class D : public B {
int f() { return 2; }
}; // f is private in D
int main()
{
D d;
B& b = d;
cout<<b.f()<<endl; // OK: B::f() is public, D::f() is invoked even though it's private
cout<<d.f()<<endl; // error: D::f() is private
}
I can't figure out why D::f() is private, D is public inherited from B, so the public function f in B
is also public in D (I know without inheritance, member access is private by default)
f is a virtual function in B, so if we call b.f(), we actually call D::f(), but just as the illustration mentioned, why D::f() is able to be invoked even though it's private?
Can anyone explain the simple inheritance problem in detail?
This has to do that with virtual dispatch is a runtime concept. The class B doesn't care which class extends it, and it doesn't care if it's private or public because it can't know.
I can't figure out why D::f() is private, D is public inherited from B, so the public function f in B
is also public in D(I know without inheritance, member access is private by default)
D::f() is private because you made it private. This rule isn't affect by inheritance nor virtual dispatch.
f is a virtual function in B, so if we call b.f(), we actually call D::f(), but just as the illustration mentioned, why D::f() is able to be invoked even though it's private?
Because in reality, when invoking b.f(), the compiler has no idea which function will actually be called. It will simply call the function f(), and since B::f is virtual, the called function will be chosen at runtime. The runtime program has no information about which function is private or protected. It only know functions.
If the function is chosen at runtime, the compiler can't know at compile-time what function will be called, and the access specifier can't be known. In fact, the compiler won't even try to check if the function called will be private or not. The access specifier could be in some code that the compiler haven't seen yet.
As you've experienced, you can't call D::f directly. This is exactly what private will do: prohibit direct access of the member. You can, however, access it indirectly through a pointer or a reference. The virtual dispatch you use will do that internally.
Access specifiers apply to the function name only, they aren't some restriction on how or when the function can be called by other means. A private function could be called outside the class if it is made available by some means other than its name (for example, a function pointer).
For a class declared with class keyword, the default access-specifier is private. Your code is the same as:
// ...
class D: public B
{
private:
int f() { return 2; }
};
As you can see, f is private in D. It makes no difference what the access specifier was of any function in B with the same name. Be clear in your mind that B::f() and D::f() are two different functions.
The effect of the virtual keyword is that if f() without a scope qualifier is called on a B reference that refers to a D object, then even though it resolves to B::f(), actually D::f() is invoked instead.
This process still uses the access specifier for B::f(): access is checked at compile-time; but it might be run-time matter as to which function is called.
The C++ Standard has an exact example of this:
11.5 Access to virtual functions [class.access.virt]
1 The access rules (Clause 11) for a virtual function are determined by its
declaration and are not affected by the rules for a function that later
overrides it. [Example:
class B {
public:
virtual int f();
};
class D : public B {
private:
int f();
};
void f() {
D d;
B* pb = &d;
D* pd = &d;
pb->f(); // OK: B::f() is public,
// D::f() is invoked
pd->f(); // error: D::f() is private
}
-- end example]
Can't explain it any clearer.
The answer given illustrates what is being done, but why would you ever want to do this, where the base class calls private virtual functions?
Well, there is a design pattern called the template method pattern that uses this technique of having a base class that calls private virtual functions in the derived class.
struct B
{
virtual ~B() {};
int do_some_algorithm()
{
do_step_1();
do_step_2();
do_step_3();
}
private:
virtual void do_step_1() {}
virtual void do_step_2() {}
virtual void do_step_3() {}
};
class D : public B
{
void do_step_1()
{
// custom implementation
}
void do_step_2()
{
// custom implementation
}
void do_step_3()
{
// custom implementation
}
};
int main()
{
D dInstance;
B * pB = &dInstance;
pB->do_some_algorithm();
}
This allows us to not expose the custom steps of class D to the public interface, but at the same time allows B to call these functions using a public function.
This actually has less to do with virtual dispatch and more to do with what access specifiers mean.
The function itself is not private; its name is.
Consequently, the function cannot be named outside of the scope of the class, e.g. from main. However, you can still do so through a name that is public (i.e. the base's virtual function that is overridden) or from a scope in which the function's name is accessible despite the private qualifier (e.g. a member function of that class).
That's just how it works.
why D::f() is able to be invoked even though it's private?
To understand virtual function mechanism it is good to know, how it is usually implemented. A function at runtime is actually no more than an address in memory where the executable code of the function body locates. To call the function we need to know its address (a pointer). C++ object with virtual functions representation in memory contains so called vtable - an array of pointers to the virtual functions.
Key point is that in derived classes vtable repeats (and may extend) the vtable of base class, but if the virtual function is overriden its pointer is replaced in derived object's vtable.
When a virtual function call is done through the base class pointer, the address of the virtual function is calculated as an offset in the vtable array. No other checks are done, just the function address is taken.
If it is a base class object, it will be the address of the base class function. If it is a derived class object, it will be the address of the derived class function, does not matter if it was declared private or not.
This how it works.
Member of struct is default to be public, and member of class is default to be private.
So f() in B is public and when it's derived to D, because you didn't explicitly declare it is public, so according to rules of derivation, it became private.
Let's imagine the following situation: A is an abstract class defining a pure virtual function void f(); B is a class that implements a function void f(); C inherits from both A and B:
struct A
{
void virtual f() =0;
};
struct B
{
virtual void f() { }
};
struct C : public A, public B
{
};
The question could be: Is C an abstract class? The requirements deriving from A being abstract are that the subclass implements the virtual function void f(). C does not implement it directly, but inherits it from B.
I can already answer this question: Yes, C is an abstract class. If you try to instantiate an object of type C you'll get a compilation error. So the actual question is: Why is C an abstract class?
I suppose that the fact that A::f and B::f have the same name and signature is not enough to draw a correspondence between these functions so to say that B::f implements A::f. From a technical point of view I can see that these functions "reside" in different parts of the object of type C (though I'm not really sure that my understanding is complete). But from a conceptual point of view I could easily imagine a situation where a class C wants to be an implementation of the abstract class A and, in order to implement the pure virtual function f, it uses the implementation of one of its parent classes. The solution is probably to do:
struct C : public A, public B
{
virtual void f() { B::f(); }
};
, which worked in my experiment. But is this trick necessary?
EDIT:
Further question: Is the order in which C inherits from A and B relevant? Would it change something if I wrote the following?
struct C : public B, public A
{
};
The answer (again, I test my codes, then I try to ask non-trivial questions) is no, it does not change anything. But in this case (correct me if I'm wrong), C::f, if implemented, would override B::f, not A::f. Since A::f would not be accessible using a C object does it make sense to request that it is implemented?
C also inherits from B doesn't make a bit of difference when it considers the functions inherited from A. So, when it compiler sees that C doesn't override pure virtual from A, it makes it an abstract class.
The requirements deriving from A being abstract are that the subclass implements the virtual function
Not quite. The requirement is that the subclass overrides the pure virtual function, with a non-pure function. A function in one base class doesn't override one in another base class; C itself must declare an override to be non-abstract.
But is this trick necessary?
Yes. You have to override the function in a class derived from A; in this case, that means C.
Is the order in which C inherits from A and B relevant?
No, the declaration order makes little difference. The override must be declared in a class derived from A.
But in this case (correct me if I'm wrong), C::f, if implemented, would override B::f, not A::f.
It would override both, regardless of the declaration order of the base classes.
Since A::f would not be accessible using a C object does it make sense to request that it is implemented?
Both are still accessible (although the name will need to be qualified since an unqualified f is ambiguous). The pure function still needs to be overridden to make the derived class non-abstract.
Since the other answers haven't been updated for your new questions, here are the answers to them.
But in this case (correct me if I'm wrong), C::f, if implemented, would override B::f, not A::f.
You're half wrong. Both A::f and B::f are overridden by C::f regardless of the order of inheritance.
Since A::f would not be accessible using a C object does it make sense to request that it is implemented?
But A::f is accessible using a C object. Consider this, rather typical use of inheritance:
void call_f(A& a) {
a.f();
}
int main() {
C c;
call_f(c);
}
If C doesn't override A::f, then this couldn't possibly work. It makes sense that a concrete subclass of A must implement A::f.
struct A{
virtual void fun(){cout<<"A";}
};
struct B:public A{
void fun(){cout<<"B";}
};
struct C:public B{
void fun(){cout<<"C";}
};
int main()
{
C c;B b1;
A *a=&b1;
a->fun(); //1
B *b=&c;
b->fun(); //2
return 0;
}
In the above code B::fun() is getting converted to virtual function implicitly as I have made A::fun() virtual. Can I stop this conversion?
If not possible what are the alternatives to make the above code print "BB" ?
A virtual function is virtual in all derived classes. There is no way to prevent this.
(ยง10.3/2 C++11) If a virtual member function vf is declared in a class Base and in a class Derived, derived directly or indirectly from Base, a member function vf with the same name, parameter-type-list (8.3.5), cv-qualification, and ref-qualifier (or absence of same) as Base::vf is declared, then Derived::vf is also virtual (whether or not it is so declared) and it overrides Base::vf. For convenience we say that any virtual function overrides itself.
However, if you'd like to use the function that corresponds to the static, rather than the dynamic, type of a pointer (i.e., in your example, B::fun instead of C::fun, given that the pointer is declared as B*), then you can, at least in C++11, use the alias definition below to get access to the static (=compile-time) type:
template <typename Ptr>
using static_type = typename std::remove_pointer<Ptr>::type;
This is how you'd use this in main() (or anywhere else):
int main()
{
C c; B b1;
A *a = &b1;
a->fun();
B *b = &c;
/* This will output 'B': */
b->static_type<decltype(b)>::fun();
return 0;
}
If you do not want your derived classes to override the function then there is no reason why you should mark it virtual in base class. The very basis of marking a function virtual is to have polymorphic behavior through derived class function overidding.
Good Read:
When to mark a function in C++ as a virtual?
If you want your code to guard you against accidental overidding in derived classes.You can use the final specifier in C++11.
Yes, if you want to explicitly call a function in a specific class you can use a fully qualified name.
b->A::fun();
This will call the version of fun() belonging to A.
The following achieves the observable behaviour you're asking for. In A, non-virtual fun() run virtual fun_() so the behaviour can be customised in B, but anyone calling fun() on a derived class will only see the non-polymorphic version.
#include <iostream>
using namespace std;
struct A{
void fun(){fun_();}
private:
virtual void fun_() { cout << "A\n"; }
};
struct B:public A{
void fun(){cout<<"B\n";}
private:
virtual void fun_() final { fun(); }
};
struct C:public B{
void fun(){cout<<"C\n";}
};
int main()
{
C c;B b1;
A *a=&b1;
a->fun(); //1
B *b=&c;
b->fun(); //2
c.fun(); // notice that this outputs "C" which I think is what you want
}
If using C++03, you can simply leave out the "final" keyword - it's only there to guard against further unwanted overrides of the virtual behaviour in B-derived classes such as C.
(You might find it interesting to contrast this with the "Nonvirtual Interface pattern" - see C++ Coding Standards by Sutter and Alexandrescu, point 39)
Discussion
A having fun virtual implies that overriding it in derived classes is a necessary customisation ability for derived classes, but at some point in the derivation hierarchy the choice of implementation behaviours might have narrowed down to 1 and providing a final implementation's not unreasonable.
My real concern is that you hide A/B's fun() with C::fun... that's troubling as if they do different things then your code could be very hard to reason about or debug. B's decision to finalise the virtual function implies certainty that there's no need for such further customisation. Code working from A*/A&/B*/B& will do one thing, while wherever a C object's type is statically known, the behaviour may differ. Templated code is one place where C::fun may easily be called without the template author or user being very conscious of it. To assess whether this is a genuine hazard for you, it would help to know what the functional purpose of "fun" is and how implementation might differ between A, B and C....
If you declare the function in B like this
void fun(int ignored=0);
it will become an overload which will not take part in resolving virtual calls. Beware that calling a->fun() will call A::fun() though even if a actually refers to a B, so I would strongly advise against this approach as it makes things even more confusing than necessary.
Question is: What exactly is it that you want to achieve or avoid? Knowing that, people here could suggest a better approach.
I have a question in virtual function and reference. It's from a puzzle when I try to prepare interview. I google it for a while but cannot see the exact case.
The code is given as:
class A{
public:
virtual void foo() {cout << "A::foo" << endl;}
};
class B: public A{
public:
void foo() {cout << "B::foo" << endl;}
};
class C: public B{
public:
void foo() {cout << "C::foo" << endl;}
};
int main(void){
C c;
B *q;
q = &c; q->foo();
return 0;
}
My thought to the output will be B::foo, but the answer is actually C::foo. Can someone tell me why the vtable wont choose B's implementation? Thanks
If foo was not virtual, then the function called would be based on the type of the pointer, and B::foo() would be called.
Since foo is defined virtual in the base class, it remains virtual in all derived classes. That being the case, the function that's called is based on the type of object pointed at rather than the type of the pointer. Since the object pointed at is a C, the function that gets called is C::foo().
foo is virtual in B because it overrides a virtual function from a base class even though it is not explicitly declared as virtual.
The most derived type of the object called through q->foo() is C and C's final overrider for foo with the signature void foo() is C::foo so this is the function that is called.
Because q points to a C object and its virtual function table contains a virtual function foo. Remember that any virtual function declared in a class is virtual in any derived class. This is the way of using base classes to access to derived ones.
Afaik:
Once vtables are used - which is in this case forced by the virtual declaration of A::foo - it's not important what type you declare, it'll always call the method of most specific method - which is in this case C::foo.
Can someone tell me why the vtable wont choose B's implementation?
That is the whole point of having virtual functions, so that calling an overriden method through a base class pointer will still call the method from the derived class.
q is of type B *, but it is pointing to a C object. So, when you call the virtual function foo() the C::foo() implementation gets called.
Even though foo() is not marked virtual in B and C, it is still a virtual function because it is declared as such in A.
If you want B::foo() to get called you'll need to call it explicitly.
q->B::foo();
foo() is a virtual function, which means that the version defined in the class whose instance is actually pointed to by q is called rather than the one defined in the class in the pointer's type.
Remember that a member function is virtual once it is marked virtual somewhere up the class hierarchy, i.e. one needs not explicitly mark the function as virtual again in classes B and C since this has already been done in class A.
I have the following classes:
class A {
public:
virtual void f() {}
};
class B : public A{
public:
void f(int x) {}
};
If I say
B *b = new B();
b->f();
the compiler says error C2660: 'B::f' : function does not take 0 arguments.
Shouldn't the function in B overload it, since it is a virtual function? Do virtual functions get hidden like this?
EDIT: I indeed meant to inherit B from A, which shows the same behaviour.
Assuming you intended B to derive from A:
f(int) and f() are different signatures, hence different functions.
You can override a virtual function with a function that has a compatible signature, which means either an identical signature, or one in which the return type is "more specific" (this is covariance).
Otherwise, your derived class function hides the virtual function, just like any other case where a derived class declares functions with the same name as base class functions. You can put using A::f; in class B to unhide the name
Alternatively you can call it as (static_cast<A*>(b))->f();, or as b->A::f();. The difference is that if B actually does override f(), then the former calls the override, whereas the latter calls the function in A regardless.
Class B does not derive from A so no function F() exists. You probably meant:
class A {
public:
virtual void f() {}
};
class B : public A {
public:
void f(int x) {}
};
Edit: I missed the actual function hiding. See Steve Jessop answer for more thorough explanation.
No, and yes, respectively. If you want the overloading behaviour, you need to say
using A::f;
in B.
B does not derive from A, the correct declaration is:
class B : public A
When the compiler has more than one way to resolve a symbol, it has to choose which one has precedence unless the code tells it otherwise. What you are expecting is the overloading to take precedence over the overriding. (over, over, over, aaaaack! Sorry, got 'over'whelmed).
This example has B inheriting a virtual method in which the subclass provides an overloaded version. Overloads are for methods in the same class using the same method name but different signatures. Since B is a subclass of A, it is overriding f(), which means it cannot also be an overload at the same time. This is why it is being hidden.
For class A, declaring method
virtual void f() {}
as virtual means that method will be resolved using a certain set of rules that are not consistent with your declaration of b.
B *b = new B();
By creating 'b' as an instance of "B", the compiler has no need to use the virtual nature of the method of the same name in "A".
If you had declared 'b' like this
B *b = new A();
then the call b->f(); would indeed refer to the method in A by making use of the virtual resolution.
It seems that it is exist rather similar question with answer in Biern Stroustrup's FAQ: http://www.stroustrup.com/bs_faq2.html#overloadderived
As he said:
"In C++, there is no overloading across scopes"
but if you want
"That's easily done using a using-declaration"