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"
Related
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.
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.
Suppose I have this:
class A
{
public:
virtual int hello(A a);
};
class B : public A
{
public:
int hello(B b){ bla bla };
};
So, A it's an abstract class.
1)In the class B, I'm defining a method that its suppose overrides the A class. But the parameter it's slightly different. I'm not sure about this, is this correct? Maybe because of polymorphism, this is ok but its rather confusing.
2) If I do: A a = new B;, and then a.hello(lol); if "lol" it's not of type B, then it would give compile error?, and if it's of type A from another class C (class C : public A), what would happend?
I'm confused about the overriding and virtual thing.. all examples I found work with methods without parameters.
Any answer, link, or whatever it's appreciated.
thanks
pd: sorry for my english
Your class B doesn't override the member function in A, it overloads it. Or tries to anyway, see the bit about hiding later.
Overriding is when a derived class defines its own version of a virtual member function from a base class. Overloading is when you define different functions with the same name.
When a virtual call is made on a pointer or reference that has the type of the base class, it will only "consider" overrides in the derived class, not overloads. This is essential - for an instance of B to be treated by callers as though it does everything an A can do (which is the point of dynamic polymorphism and virtual functions), its hello function needs to be able to take any object of type A. A hello function which only takes objects of type B, rather than any A, is more restrictive. It can't play the role of A's hello function, so it's not an override.
If you experiment a bit with calling hello on A and B, passing objects of type A or B, you should be able to see the difference. A has a function taking an A (which you haven't defined, so if you call it then your program will fail to link, but you can fix that). B has a function taking a B. They happen to have the same name, and of course since B derives from A, you can pass a B to the function taking an A. But B's function doesn't act as an override in virtual calls.
It is possible to call A's function on a B object, but only via a reference or pointer to A. A feature of C++ is that the definition of hello in B hides the definition in A. If overloading is what you want, it's possible to un-hide the base class function by adding using A::hello; to class B. If overriding is what you want, you have to define a function taking the same parameters. For example:
#include <iostream>
class A
{
public:
virtual int hello(A a) {std::cout << "A\n"; }
virtual int foo(int i) { std::cout << "A::Foo " << i << "\n"; }
};
class B : public A
{
public:
using A::hello;
// here's an overload
int hello(B b){ std::cout << "B\n"; };
// here's an override:
virtual int foo(int i) { std::cout << "B::Foo " << i << "\n"; }
};
int main() {
A a;
B b;
a.hello(a); // calls the function exactly as defined in A
a.hello(b); // B "is an" A, so this is allowed and slices the parameter
b.hello(a); // OK, but only because of `using`
b.hello(b); // calls the function exactly as defined in B
A &ab = b; // a reference to a B object, but as an A
ab.hello(a); // calls the function in A
ab.hello(b); // *also* calls the function in A, proving B has not overridden it
a.foo(1); // calls the function in A
b.foo(2); // calls the function in B
ab.foo(3); // calls the function in B, because it is overridden
}
Output:
A
A
A
B
A
A
A::Foo 1
B::Foo 2
B::Foo 3
If you take away the using A::hello; line from B, then the call b.hello(a); fails to compile:
error: no matching function for call to `B::hello(A&)'
note: candidates are: int B::hello(B)
A bunch of good answers telling you WHAT happens, I thought I'd jump in with WHY.
There's this thing called the Liskov Substitution Principle, which says that the function in the subclass has to work under the same preconditions and postconditions as the base class. In this case, the function has to be able to operate on any object of type A. Note that because of the inheritance relationships, every B is-a A, but not every A is-a B. So to replace the base method, the new function in the derived class can weaken the preconditions or strengthed the postconditions, but not strengthen preconditions or weaken postconditions.
Your attempt to override strengthens the precondition, it accepts Bs, not all As.
Note that covariance IS allowed on return types. If your base class returned A, then it guarantees that the return value is-a A. The base class could then return a B, because every B is-a A.
But for input parameters, only contravariance meets the theoretical requirements of the LSP, and in/out parameters are invariants. In C++ in particular, all parameter types are invariant for the purposes of overloading.
First, A is not an abstract class in your code. It must have at least one pure virtual function to be abstract.
different parameters means completely different method, even though the name is the same. Think of it as a different name. That's why it's called "signature". If A would be an abstract class, this code would not compile at all.
A::hello() will be called. No problem with that, and parameter must be type A, as if there was no inheritance.
When you override a method, it redefines what the method will do. You can only override virtual members that are already defined (with their set of parameters). If the type is of A, the method on A will be called. If the type is of B, the method on B will be called even if the variable is typed A but contains an instance of type B.
You can't change the parameter definitions for an overridden method, or else it would cease to be an override.
What you are doing there is overloading not overriding, i.e. it's as if class B is:
class B
{
public:
int hello(A a) {...}
int hello(B b) {...}
};
You have two functions of the same name, but with different signatures, which makes them different functions (just like the standard library has different functions for abs(float) and abs(double) etc.)
If you want to override, then you need to have the same signature, i.e. class B's hello needs to take a parameter of type A. That way, when you call hello on an object of class B, it will use class B's hello rather than class A's.
If you actually want class B's hello to only accept objects of type B then what you have is fine, although you probably want to make class A's hello non-virtual as you are not really wanting to override it -- you are defining a new function with new parameters and new behaviour.
Thansk for the answers, but I have to clarify some things to get my final answer.
Suppose I have the A class exactly how I defined it in the original question. And I add another method:
class A {
...
int yeah();
}
Then I define class B as the following:
class B : public A {
int hello(A a);
};
And another class C analogous to B.
What I know because I'm the programmer, it's that the hello methods of B and C are gonna have obviously A type objects as parameters, but instances of the same class.
In example:
B b;
b.hello(some_other_b_instance);
or
C c;
c.hello(some_other_c_instance);
The problem is that in each hello function of the classes B and C, I want to do particular things with atributes of the particular class B or C. And because of the parameter is of type A, I cannot use them.
What I would need it's a kind of inverse polymorphysm, but its wrong because by definition I can send a C instance to B hello class, but I know it's not gonna happend.
I hope you get the idea of the code... A clase is abstract, and the real work makes sense in the particular clases B and C, each one do the work in their particular way to make the yeah function work. But B and C need to access their members to do the hello work correctly.
#include<iostream>
using namespace std;
class A
{
int a;
int b;
public:
void eat()
{
cout<<"A::eat()"<<endl;
}
};
class B: public A
{
public:
void eat()
{
cout<<"B::eat()"<<endl;
}
};
class C: public A
{
public:
void eat()
{
cout<<"C::eat()"<<endl;
}
};
class D: public B, C
{
};
int foo(A *ptr)
{
ptr->eat();
}
main()
{
D obj;
foo(&(obj.B)); //error. How do i call with D's B part.
}
The above foo call is a compile time error.
I want to call foo with obj's B part without using virtual inheritance. How do i do that.
Also, in case of virtual inheritance, why the offset information need to be stored in the vtable. This can be determined at the compile time itself. In the above case, if we pass foo with D's object, at compile time only we can calculate the offset of D's A part.
Inheriting twice
With double inheritance you have an ambiguity - the compiler cannot know which of the two A bases do you want to use. If you want to have two A bases (sometimes you may want to do this), you may select between them by casting to B or C. The most appropriate from default casts here is the static_cast (as the weakest available), however it is not realy needed (it is still stronger than your case needs), as you are not casting to a derived type. A custom safe_cast template should do the job:
/// cast using implicit conversions only
template <class To,class From>
inline To safe_cast( const From &from ) {return from;}
main()
{
D obj;
foo(safe_cast<B *>(&obj)); //error. How do i call with D's B part.
}
Compile time types - use templates
Also, in case of virtual inheritance,
why the offset information need to be
stored in the vtable. This can be
determined at the compile time itself.
In the above case, if we pass foo with
D's object, at compile time only we
can calculate the offset of D's A
part.
This is a misconception. The foo function as it is written now has no compile type information about ptr type other than it is A *, even if you pass B * or C*. If you want foo to be able to act based on the type passed compile time, you need to use templates:
template <class TypeDerivedFromA>
int foo(TypeDerivedFromA *ptr)
{
ptr->eat();
}
Virtual Inheritance
Your questions mentions virtual inheritance. If you want to use virtual inheritance, you need to specify so:
class B: public virtual A ...
class C: public virtual A ...
With this the code would compile, but with this solution there is no way you could select between B::A or C::A (there is only one A), therefore this is probably not what you are about.
Virtual functions
Furthermore, your questions seems to be confusing two different concepts, virtual inheritance (which means sharing one base class between two intermediate base classes) and virtual functions (which mean allowing derived class function to be called via base class pointer). If you want the B::eat to be called using A pointer, you can do this without virtual inheritance (actually virtual inheritance would prevent you doing so, as explained above), using virtual functions:
class A
{
int a;
int b;
public:
virtual void eat()
{
cout<<"A::eat()"<<endl;
}
};
If virtual functions are not acceptable for you, the compile time mechanism for this are templates, as explained above.
Use a cast - static_cast is required here to cast up the heirarchy.
main()
{
D obj;
foo(static_cast<B*>(&obj));
}
First of all, obj does not have a member named B. It Inherits from B, which means that it inherits all of B's members as its own.
You can call:
foo(static_cast<B*>(&obj)); to make it work.
I don't think the static_cast will work.
When you are on the foo function, all the compiler knows is that you have a pointer to A, whatever the type you passed as parameter.
If you don't use virtual inheritance, then I think there is no way to call a B function from a pointer to A.