Question on Virtual Function

Just as the code below:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class A {
public:
	virtual int func(int i = 1) {
		std::cout << "class A" << std::endl;
		return i + 1;
	}
	virtual ~A() {}
};

class B :public A {
public:
	virtual int func(int i = 10) {
		std::cout << "class B " << i << std::endl;
		return i;
	}
};
int main(int argc, char* argv[]) {
	A* p = new B();
	p->func();
	delete p;
	return 0;
}

The output of the code ("class B 1") confuses me. I wonder what happened. I think the key is the default arguments in virtual function.
Thanks for you help.
On line 19 the compiler assumes that the function func() of class A is used hence the default value 1 is passed to func().
https://stackoverflow.com/questions/3533589/can-virtual-functions-have-default-parameters

The default arguments are determined "statically" (at compile time), so as coder777 said, all it sees is that the A class is being dereferenced, so it applies A's default argument. It isn't until runtime that it looks up that it actually needs to call the subclass.

Code like this is fragile and I would avoid it when possible.
http://www.gotw.ca/gotw/005.htm
Herb Sutter wrote:
Unless you're really out to confuse people, don't change the default parameters of the inherited functions you override. (In general, it's not a bad idea to prefer overloading to parameter defaulting anyway, but that's a subject in itself.)
Last edited on
Got it.
Thanks for your reply.
p is of type pointer A - so the default value from A.func() is used.

If p is made pointer to B, then the default value from B.func() is used.

Note that if a member function of a base class is being overridden, you can specify override on the overridden function so that the compiler can check that the function is indeed overridden. Also virtual is not needed for virtual overridden functions. Consider:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream>

class A {
public:
	virtual int func(int i = 1) {
		std::cout << "class A\n";
		return i + 1;
	}

	virtual ~A() {}
};

class B : public A {
public:
	int func(int i = 10) override {
		std::cout << "class B " << i << '\n';
		return i;
	}
};

class C : public B {
public:
	int func(int i = 100) override {
		std::cout << "class C " << i << '\n';
		return i;
	}

};

int main() {
	B* p { new C };

	p->func();
	delete p;
}


which displays


10


as p is of type pointer B.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>

class A {
public:
    virtual void func(int i = 1) {
    std::cout << "class A " << i << '\n';
    return;
}

    virtual ~A() {}
};

class B : public A {
public:
    void func(int i = 10) override {
    // i = 10; // new definition
    std::cout << "class B " << i << '\n';
    return;
    }
};

int main() 
{
    A* p { new B };

    p->func();
    delete p;
}


If I understand correctly, when we use some virtual function (including parameters by default), we have to set the new parameters even if they are declared in the overriden function?
Last edited on
What?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>

class A {
public:
    virtual void func(int i = 1) {
        std::cout << "class A " << i << '\n';
    }

    virtual ~A() {}
};

class B : public A {
public:
    void func(int i) override {  // OK
        std::cout << "class B " << i << '\n';
    }
};

int main() 
{
    B b;
    A* p { &b };
    p->func();
    p->func(2);

    B* r { &b };
    r->func(3);
    r->func(); // error: too few arguments to function call, expected 1, have 0;
}
Topic archived. No new replies allowed.