Understanding Virtual functions [duplicate] - c++

If I declare a base class (or interface class) and specify a default value for one or more of its parameters, do the derived classes have to specify the same defaults and if not, which defaults will manifest in the derived classes?
Addendum: I'm also interested in how this may be handled across different compilers and any input on "recommended" practice in this scenario.

Virtuals may have defaults. The defaults in the base class are not inherited by derived classes.
Which default is used -- ie, the base class' or a derived class' -- is determined by the static type used to make the call to the function. If you call through a base class object, pointer or reference, the default denoted in the base class is used. Conversely, if you call through a derived class object, pointer or reference the defaults denoted in the derived class are used. There is an example below the Standard quotation that demonstrates this.
Some compilers may do something different, but this is what the C++03 and C++11 Standards say:
8.3.6.10:
A virtual function call (10.3) uses
the default arguments in the
declaration of the virtual function
determined
by the static type of the pointer or reference denoting the object. An
overriding function in a derived
class does not acquire default arguments from the function it
overrides. Example:
struct A {
virtual void f(int a = 7);
};
struct B : public A {
void f(int a);
};
void m()
{
B* pb = new B;
A* pa = pb;
pa->f(); //OK, calls pa->B::f(7)
pb->f(); //error: wrong number of arguments for B::f()
}
Here is a sample program to demonstrate what defaults are picked up. I'm using structs here rather than classes simply for brevity -- class and struct are exactly the same in almost every way except default visibility.
#include <string>
#include <sstream>
#include <iostream>
#include <iomanip>
using std::stringstream;
using std::string;
using std::cout;
using std::endl;
struct Base { virtual string Speak(int n = 42); };
struct Der : public Base { string Speak(int n = 84); };
string Base::Speak(int n)
{
stringstream ss;
ss << "Base " << n;
return ss.str();
}
string Der::Speak(int n)
{
stringstream ss;
ss << "Der " << n;
return ss.str();
}
int main()
{
Base b1;
Der d1;
Base *pb1 = &b1, *pb2 = &d1;
Der *pd1 = &d1;
cout << pb1->Speak() << "\n" // Base 42
<< pb2->Speak() << "\n" // Der 42
<< pd1->Speak() << "\n" // Der 84
<< endl;
}
The output of this program (on MSVC10 and GCC 4.4) is:
Base 42
Der 42
Der 84

This was the topic of one of Herb Sutter's early Guru of the Week posts.
The first thing he says on the subject is DON'T DO THAT.
In more detail, yes, you can specify different default parameters. They won't work the same way as the virtual functions. A virtual function is called on the dynamic type of the object, while the default parameter values are based on the static type.
Given
class A {
virtual void foo(int i = 1) { cout << "A::foo" << i << endl; }
};
class B: public A {
virtual void foo(int i = 2) { cout << "B::foo" << i << endl; }
};
void test() {
A a;
B b;
A* ap = &b;
a.foo();
b.foo();
ap->foo();
}
you should get
A::foo1
B::foo2
B::foo1

This is a bad idea, because the default arguments you get will depend on the static type of the object, whereas the virtual function dispatched to will depend on the dynamic type.
That is to say, when you call a function with default arguments, the default arguments are substituted at compile time, regardless of whether the function is virtual or not.
#cppcoder offered the following example in his [closed] question:
struct A {
virtual void display(int i = 5) { std::cout << "Base::" << i << "\n"; }
};
struct B : public A {
virtual void display(int i = 9) override { std::cout << "Derived::" << i << "\n"; }
};
int main()
{
A * a = new B();
a->display();
A* aa = new A();
aa->display();
B* bb = new B();
bb->display();
}
Which produces the following output:
Derived::5
Base::5
Derived::9
With the aid of the explanation above, it is easy to see why. At compile time, the compiler substitutes the default arguments from the member functions of the static types of the pointers, making the main function equivalent to the following:
A * a = new B();
a->display(5);
A* aa = new A();
aa->display(5);
B* bb = new B();
bb->display(9);

As other answers have detailed, its bad idea. However since no one mentions simple and effective solution, here it is: Convert your parameters to struct and then you can have default values to struct members!
So instead of,
//bad idea
virtual method1(int x = 0, int y = 0, int z = 0)
do this,
//good idea
struct Param1 {
int x = 0, y = 0, z = 0;
};
virtual method1(const Param1& p)

As you can see from the other answers this is a complicated subject. Instead of trying to do this or understand what it does (if you have to ask now, the maintainer will have to ask or look it up a year from now).
Instead, create a public non-virtual function in the base class with default parameters. Then it calls a private or protected virtual function that has no default parameters and is overridden in child classes as needed. Then you don't have to worry about the particulars of how it would work and the code is very obvious.

This is one that you can probably figure out reasonably well by testing (i.e., it's a sufficiently mainstream part of the language that most compilers almost certainly get it right and unless you see differences between compilers, their output can be considered pretty well authoritative).
#include <iostream>
struct base {
virtual void x(int a=0) { std::cout << a; }
virtual ~base() {}
};
struct derived1 : base {
void x(int a) { std:: cout << a; }
};
struct derived2 : base {
void x(int a = 1) { std::cout << a; }
};
int main() {
base *b[3];
b[0] = new base;
b[1] = new derived1;
b[2] = new derived2;
for (int i=0; i<3; i++) {
b[i]->x();
delete b[i];
}
derived1 d;
// d.x(); // won't compile.
derived2 d2;
d2.x();
return 0;
}

Related

What would be a use case for dynamic_cast of siblings?

I'm reading Scott Meyers' More Effective C++ now. Edifying! Item 2 mentions that dynamic_cast can be used not only for downcasts but also for sibling casts. Could please anyone provide a (reasonably) non-contrived example of its usage for siblings? This silly test prints 0 as it should, but I can't imagine any application for such conversions.
#include <iostream>
using namespace std;
class B {
public:
virtual ~B() {}
};
class D1 : public B {};
class D2 : public B {};
int main() {
B* pb = new D1;
D2* pd2 = dynamic_cast<D2*>(pb);
cout << pd2 << endl;
}
The scenario you suggested doesn't match sidecast exactly, which is usually used for the casting between pointers/references of two classes, and the pointers/references are referring to an object of class which both derives from the two classes. Here's an example for it:
struct Readable {
virtual void read() = 0;
};
struct Writable {
virtual void write() = 0;
};
struct MyClass : Readable, Writable {
void read() { std::cout << "read"; }
void write() { std::cout << "write"; }
};
int main()
{
MyClass m;
Readable* pr = &m;
// sidecast to Writable* through Readable*, which points to an object of MyClass in fact
Writable* pw = dynamic_cast<Writable*>(pr);
if (pw) {
pw->write(); // safe to call
}
}
LIVE
It is called cross-cast, and it is used when a class inherits from two different classes (not the other way around, as shown in your question).
For example, given the following class-hierarchy:
A B
\ /
C
If you have an A pointer to a C object, then you can get a B pointer to that C object:
A* ap = new C;
B* bp = dynamic_cast<B*>(ap);

default parameter in virtual functions C++

I read about the inheritance mechanism in C++ and about virtual functions.
according to my knowlendge (in all examples I have encountered), inherited methods had the same signature as the parent class'.
My question is the following:
I know that function default parameter value is not a part of function signature.
Can I define this value to be some constant in the parent Class virtual function, and in the derived class declare and implement the overriding method without this default value.
In this case, when I call the derived object's method using a pointer to parent class, will the function be called with/without this default initializion?
thanks
Default arguments are mostly syntactic sugar and get determined at compile time. Virtual dispatch, on the other hand, is a run-time feature. It would probably be least surprising to have that default parameter chosen that was defined alongside with the function that actually gets called but this is not possible (at least not without additional run-time overhead) for the reason stated above.
Therefore, the default parameter is selected by the compiler using the static type of the object a member function is called upon. Let's see an example.
#include <iostream>
#include <memory>
class Base
{
public:
virtual void
f(int a, int b = 1)
{
std::cout << "Base: a = " << a << ", b = " << b << "\n";
}
};
class Derived : public Base
{
public:
virtual void
f(int a = 1, int b = 2) override
{
std::cout << "Derived: a = " << a << ", b = " << b << "\n";
}
};
int
main()
{
std::unique_ptr<Base> base_as_base {new Base {}};
std::unique_ptr<Base> derived_as_base {new Derived {}};
std::unique_ptr<Derived> derived_as_derived {new Derived {}};
base_as_base->f(0); // Base: a = 0, b = 1
derived_as_base->f(0); // Derived: a = 0, b = 1
// derived_as_base->f(); // compiler error
derived_as_derived->f(0); // Derived: a = 0, b = 2
derived_as_derived->f(); // Derived: a = 1, b = 2
}
I agree that this is confusing. Please don't write code like this. Fortunately, there is a simple workaround. Apart from not using default parameters at all, we can use an idiom called non-virtual interfaces. The virtual function is made protected and not given any default parameters. It is then only called indirectly by a non-virtual function from the base class. That function can have all default parameters defined in a single place.
#include <iostream>
#include <memory>
class Base
{
public:
void
f(int a, int b = 1)
{
this->impl(a, b);
}
protected:
virtual void
impl(int a, int b)
{
std::cout << "Base: a = " << a << ", b = " << b << "\n";
}
};
class Derived : public Base
{
protected:
virtual void
impl(int a, int b) override
{
std::cout << "Derived: a = " << a << ", b = " << b << "\n";
}
};
int
main()
{
std::unique_ptr<Base> base_as_base {new Base {}};
std::unique_ptr<Base> derived_as_base {new Derived {}};
std::unique_ptr<Derived> derived_as_derived {new Derived {}};
base_as_base->f(0); // Base: a = 0, b = 1
derived_as_base->f(0); // Derived: a = 0, b = 1
derived_as_derived->f(0); // Derived: a = 0, b = 1
}
This is what I found from the C++ Draft Standard N3337:
8.3.6 Default arguments
10 A virtual function call (10.3) uses the default arguments in the declaration of the virtual function determined by the static type of the pointer or reference denoting the object. An overriding function in a derived class does not acquire default arguments from the function it overrides. [ Example:
struct A {
virtual void f(int a = 7);
};
struct B : public A {
void f(int a);
};
void m() {
B* pb = new B;
A* pa = pb;
pa->f(); // OK, calls pa->B::f(7)
pb->f(); // error: wrong number of arguments for B::f()
}
—end example ]
Coming to your question:
Can I define this value to be some constant in the parent Class virtual function,
Yes
and in the derived class declare and implement the overriding method without this default value
Yes.
However, when you call the function using a derived class pointer, you'll have to provide an argument. When you call the function using a base class pointer, you don't need to provide an argument.

Declare static, constant member in abstract base class, assign it to a value in derived class?

I have an abstract base class and a pair of classes derived from this base class. I would like to introduce a static const member that has a different value between the two derived classes but the same value for all instances of a given derived class.
I have code which uses a base class pointer assigned to an instance of one of the two derived classes so that I can easily switch between derived classes by changing what the base class pointer is assigned to. I would like to be able to obtain the value of the derived class' constant value using the base class in a similar way so that I can easily switch between the two classes. The desired behavior looks something like this:
#include <iostream>
using namespace std;
// Abstract base class
class A {
protected:
int c; // this is really a constant and should also be static
public:
static int s;
int get_c() const {
return this->c;
}
virtual int foo() = 0; // makes this class abstract
};
class B : public A {
public:
static const int sb = 10;
B() {
this->c = 1;
}
int foo() {
return -1;
}
};
class C : public A {
public:
static const int sc = 20;
C() {
this->c = 2;
}
int foo() {
return -2;
}
};
int main() {
B btest;
C ctest;
A *ptr = &btest; // pointer to instance of B
//cout << ptr->c << endl; // would fail compilation (c is protected)
cout << "B's c = " << ptr->get_c() << endl;
cout << "B's foo() returns " << ptr->foo() << endl;
cout << "Accessing B's static const member: " << B::sb << endl;
ptr = &ctest; // pointer to instance of C
//cout << ptr->c << endl; // would fail compilation (c is protected)
cout << "C's c = " << ptr->get_c() << endl;
cout << "C's foo() returns " << ptr->foo() << endl;
cout << "Accessing C's static const member: " << C::sc << endl;
return 0;
}
In the above code sb and sc are the static const members I want, but the problem with them is that base class A has no knowledge of them. The base class member c is doing what I want but is not static const as desired (I've made c a protected member so that it cannot be modified, but if I can declare it const then it can be public). This code has the desired behavior from c:
I can get a distinct value for c from each derived class using a base class pointer.
c is effectively constant since it is protected and I provide no setter function.
However, c isn't really constant in that it isn't const and it isn't static so every instance has an unnecessary copy of it.
Is there a way to get the desired behavior and also declare c with static const like sb and sc?
You can't implement this with a static variable in A; that will be common to all subtypes of A, so you can't get a different value for each subtype. Since the dynamic type of the object behind a base-class pointer is only known at run-time, you'll need a run-time mechanism to get the value from it.
This could use a per-object variable, which can be const if you initialise it in the constructor:
class A {
// ...
const int c;
A(int c) : c(c) {}
};
class B : public A {
// ...
B() : A(1) {}
};
class C : public A {
// ...
C() : A(2) {}
};
or a virtual function that each subclass overrides to return a different value:
class A {
// ...
int get_c() const = 0;
};
class B : public A {
// ...
int get_c() const {return 1;}
};
class C : public A {
// ...
int get_c() const {return 2;}
};
Both options meet both your requirements; one has the cost of a virtual function call on access, while the other has the cost of a per-object variable. You'll have to decide which cost is more suitable for your needs.

Strange behavior with virtual functions

With the following code, I would expect output to be B.f B.f DD.f, but instead the output I get is B.f B.f B.f. How is that possible, when DD derives from D which has f as virtual.
class B
{
public:
void f() { cout << "B.f "; }
};
class D : public B
{
public:
virtual void f() { cout << "D.f "; }
};
class DD : public D{
public:
virtual void f() { cout << "DD.f "; }
};
B * b = new B();
B * d = new D();
B * dd = new DD();
b->f();
d->f();
dd->f();
Functions become virtual from the level they were declared virtual up. You first declare f virtual in D, which means the dynamic dispatch will only happen from D upwards. B doesn't, nor should it know about the deriving classes.
Think about how the compiler sees it:
You have a pointer to B - B has the following definition:
class B
{
public:
void f() { cout << "B.f "; }
};
Since f is not virtual, I'll just go ahead and resolve the call statically - i.e. B::f().
For dynamic dispatch to work from a pointer to B, you need to make f() virtual in B:
class B
{
public:
virtual void f() { cout << "B.f "; }
};
You need to set B::f() to virtual, without set B::f() to virtual, it won't appear in B virtual table(vtbl), thus B::f() is called instead of dispatch the call to derived class.
class B
{
public:
virtual void f() { cout << "B.f "; }
};
As soon as you declare f() virtual in B,this starts to maintain a virtual table that holds the function pointers of all the other functions of same name of derived classes. This is a lookup table that is used to resolve function calls in a dynamic/late binding manner.
When you use a reference or a pointer to call a method, the compiler searches in the type of the pointer or reference at the declaration of the method (here it searches in B the declaration of some method with signature f()). When it finds one :
if it is NOT marked as virtual, then it solves it as a call to the method defined for this class - this is a static binding.
if it is marked as virtual, then the method called will be the appropriate one of the object referenced or pointed by - this is a dynamic binding.
The next test would have been :
DD * dd = new DD();
D * d = dd;
B * b = d;
b->f();
d->f();
dd->f();
One single object new DD() that is used/viewed differently... Each type can be thought as a kind of view you have on an object. If you see it as a B then f() does something but always the same thing, but if you see it as D or DD, f() does something different...
If you meet someone in the street, the standard way for him to salute you is to say hello, but for the same person, when he meets a friend of him he can either say hi! or Yo! :
class Person {
public:
void salute() { cout << "Hello" << endl; }
};
class Friend : public Person {
public:
virtual void salute() { cout << "Hi!" << endl; }
};
class RoomMate : public Friend {
public:
virtual void salute() { cout << "Yo!" << endl; }
};
void asACustomer(Person &p) {
p.salute(); // static binding, we need the standard politeness
}
void asAFriend(Friend &f) {
p.salute(); // dynamic binding, we want an appropriate message...
}
RoomMate joe;
asCustomer(joe);
asFriend(joe);
With static binding you know at compile time which method is called; with dynamic binding you cannot, you only know that an appropriate one will be. This is a key point in sub-typing polymorphism.
In general, be careful when mixing static and dynamic binding for a method.

Implement two functions with the same name but different, non-covariant return types due to multiple abstract base classes

If I have two abstract classes defining a pure virtual function with the same name, but different, non-covariant return types, how can I derive from these and define an implementation for both their functions?
#include <iostream>
class ITestA {
public:
virtual ~ITestA() {};
virtual float test() =0;
};
class ITestB {
public:
virtual ~ITestB() {};
virtual bool test() =0;
};
class C : public ITestA, public ITestB {
public:
/* Somehow implement ITestA::test and ITestB::test */
};
int main() {
ITestA *a = new C();
std::cout << a->test() << std::endl; // should print a float, like "3.14"
ITestB *b = dynamic_cast<ITestB *>(a);
if (b) {
std::cout << b->test() << std::endl; // should print "1" or "0"
}
delete(a);
return 0;
}
As long as I don't call C::test() directly there's nothing ambiguous, so I think that it should work somehow and I guess I just didn't find the right notation yet. Or is this impossible, if so: Why?
Okay, it is possible, and the way isn't too ugly. I have to add an additional level of inheritance:
ITestA ITestB <-- These are the interfaces C has to fulfill, both with test()
| |
ITestA_X ITestB_X <-- These classes implement the interface by calling a
| | function with a different name, like ITestA_test
\__________/ which is in turn pure virtual again.
|
C <-- C implements the new interfaces
Now C has no function test(), but when casting a C* to an ITestA*, the implementation of test() in ITestA_test will be used. When casting it to an ITestB*, even by a dynamic_cast from the ITestA*, the implementation of ITestB_test will be used.
The following program prints:
3.14
0
#include <iostream>
class ITestA {
public:
virtual ~ITestA() {};
virtual float test() =0;
};
class ITestB {
public:
virtual ~ITestB() {};
virtual bool test() =0;
};
class ITestA_X : public ITestA {
protected:
virtual float ITestA_test() =0;
virtual float test() {
return ITestA_test();
}
};
class ITestB_X : public ITestB {
protected:
virtual bool ITestB_test() =0;
virtual bool test() {
return ITestB_test();
}
};
class C : public ITestA_X, public ITestB_X {
private:
virtual float ITestA_test() {
return 3.14;
}
virtual bool ITestB_test() {
return false;
}
};
int main() {
ITestA *a = new C();
std::cout << a->test() << std::endl;
ITestB *b = dynamic_cast<ITestB *>(a);
if (b) {
std::cout << b->test() << std::endl;
}
delete(a);
return 0;
}
Does this have any drawbacks you could think of?
When you declare ITestA *a = new C(), you have created a C object. If you invoke test on it with a->test(), it has to use the C virtual table to find the code to execute. But C is trying to have two different implementations of the same signature test(), which isn't allowed. The fact that you declared it as an ITestA * doesn't affect the method resolution. You declared the methods virtual, so they are found via the actual type of the object, regardless of the type of the pointer you used to access it.
You cannot have two methods with the same name and argument types. You'll need to find another way to structure this code.
I don't think this is possible. Functions overload by name (and signature).