I don't understand what is wrong with this code. It looks like an incredible trap !
This code :
class Foo
{
public:
virtual double foo(double x) const = 0;
double foo(int x) const { return (double)(x + x); }
};
class Bar : public Foo
{
public:
virtual double foo(double x) const { return x * x; }
};
int main()
{
Bar* b = new Bar;
Foo* f = b;
std::cout << b->foo(3) << " " << f->foo(3) << std::endl;
std::cout << b->foo(5.0) << " " << f->foo(5.0) << std::endl;
return 0;
}
prints the following output :
9 6
25 25
I deduce that Bar::foo(double) const is called with an implicit cast when the type of the pointer is Bar*. But why such a thing is possible without any warning ?
I work with GCC 4.7.2. I compiled with g++ -Wall foobar.cpp -o foobar.exe
This is due to name hiding.
When you declare a function called foo in Bar, you hide all declarations with the same name in Foo.
As such, when the static type of the pointer is Bar, the compiler only finds the version in Bar which takes a double, so it implicitly converts the int to satisfy this.
If you want the int version in Foo to be visible, add a using declaration:
class Bar : public Foo
{
public:
using Foo::foo;
// ^^ makes the versions in Foo visible
virtual double foo(double x) const { return x * x; }
};
When the type is Bar*, only one version of the method is visible, the one with the double parameter.
Base methods with the same name (but different signature) are hidden.
To make them available, you can use using Foo::foo in the derived class.
Depending on your compiler, I think you might also get warnings regarding the implicit conversion, or the fact that you apparently want to call a hidden method.
In Foo there are two overloads of foo, one that takes a double and another that takes an int.
In Bar there is one overload of foo, the one that takes a double. This overload hides all functions with the same name from the base classes. This is called name hiding.
A fix would be to employ using declaration to bring the other foo overloads from the base class in scope of Foo derived class:
class Bar : public Foo
{
public:
using Foo::foo;
virtual double foo(double x) const { return x * x; }
};
Related
First of all, sorry for the confusing title. I have no idea how to word this properly.
The problem is not really a problem, but rather something that I don't know how to implement.
Here is the code:
#include <iostream>
class Parent
{
public:
virtual void foo()
{
std::cout << "Parent's foo" << std::endl;
}
void bar()
{
foo();
}
};
class Child : public Parent
{
public:
void foo()
{
std::cout << "Child's foo" << std::endl;
}
};
int main()
{
Child c;
c.bar();
return 0;
}
When the code above runs, it prints outChild's foo.
However the same code, BUT with the child classes foo definition beingvoid foo(bool def = true)Prints out Parent's foo.
Is there anyway to call the child's version of foo instead of the parent's one if the definitions missmatch?
Unfortunately not, if you want to add extra parameters, even default ones, you can create an overloaded function explicitly, which behaves similar in most cases to the caller.
#include <iostream>
class Parent
{
public:
virtual void foo()
{
std::cout << "Parent's foo" << std::endl;
}
void bar()
{
foo();
}
};
class Child : public Parent
{
public:
virtual void foo(bool def) // virtual if another subclass needs to override
{
std::cout << "Child's foo def = " << def << std::endl;
}
virtual void foo()override //override and virtual optional here
{
foo(true);
}
};
int main()
{
Child c;
c.bar();
c.foo();
c.foo(true);
return 0;
}
This is purely a function of when a function is overridden in C++.
In C++, function overriding is done according to the "signature" of member functions:
unqualified name
exact parameters list in the declaration (excluding implicit this)
qualification of the this implicit parameter
Obviously, by definition, the type of the this parameter cannot match exactly, as by definition the type must be a pointer to a derived class.
[Note about cv-qualification on parameters:
The parameters in the declaration as seen by caller must be exactly the same, that is after removal of meaningless cv-qualifiers on object copies: these are cv-qualifiers on local variables inside the function body, and that's only meaningful in a function definition.
void f(const int i); // takes an int by value; const is meaningless
void f(int i); // redeclaration of the same function
// redeclaration of the same function yet again
void f(const int ci) { // const is meaningful here
ci = 1; // error
}
--end note]
However the same code, BUT with the child classes foo definition
being void foo(bool def = true) Prints out Parent's foo.
Because there is no match of the parameters lists: an empty parameter list is only matched by an empty parameter list.
You need to replace the default argument with two overloaded functions here, with no forwarding to the other:
void foo(bool def); // new function signature
void foo() { // overrides Parent's member
foo(true);
}
With long complex a parameters list, it's easy to change a type and create a new function signature instead of overriding a base class virtual function; it's also easy to get the capitalisation wrong or spelling wrong (think English vs. US spelling). In general, getting the name of a function wrong (or any other name: of a type, of a template, of a variable...) causes a compilation error because that name with the small spelling change wasn't declared. But with a raw declaration of a member with the intent of overriding a base class declaration, there is no hint that you tried to do that and the compiler will not warn you (it might warn for hiding a base class declaration, but this is different). Explicitly marking a declaration intended to be an override with the virtual keyword doesn't help, introducing a new virtual function isn't the intent.
That was the sad state of affairs after the first version of the C++ standard was formalized. Now it's different.
If you want to be sure that you are indeed overriding a base class declaration, you can now use the override keyword:
class Child : public Parent
{
public:
void foo(bool def);
void foo() override {
foo(true);
}
};
I've got weird thing which, by my experience, I can call bug in C++. When I call this program:
#include <iostream>
using namespace std;
class foo {
public:
int a;
foo(int a = 0) : a(a) {}
} a1;
class bar {
foo a;
public:
bar(foo a = a1) : a(a) {
a.a = 1;
cout << a.a << endl;
}
void print_a() {
cout << a.a << endl;
}
};
int main() {
bar zz;
zz.print_a();
a1.a = 2;
bar zz1;
zz1.print_a();
}
The output is:
1
0
1
2
I do expect to be able to change values of internal members of my class, like the a value of the object of foo class inside bar class. When I change the a.a value in bar constructor, it looks like I changed only local variable. What is the mechanism of this process? C++ does not treat variables inside its class as constant parameters, because I can as well get counter which is changed by methods. But when counter is one class more deeper, the structure seems to collapse.
Within the constructor body, argument names hide member names, so as you surmised, you're modifying the function argument a, not the member a.
You can refer to the member as this->a or bar::a to disambiguate, if you don't want to rename either variable.
i have a question regarding calling a function with virtual methods and multiple inheritence.
i have the following code:
#include<iostream>
using namespace std;
class A{};
class B:public A{};
class C:public B{};
class AA:public A{};
struct X
{
void f(A*) { std::cout<< "X::f(A*)\n";}
virtual void f(B*) { std::cout<< "X::f(B*)\n";}
void f(C*) { std::cout<< "X::f(C*)\n";}
virtual void f(C*) const { std::cout<< "const X::f(C*)\n";}
};
struct Y:public X {
virtual void f(B*) { std::cout<< "Y::f(B*)\n";}
void f(A*) { std::cout<< "Y::f(A*)\n";}
virtual void f(C*) const { std::cout<< "const Y::f(C*)\n";}
};
int main() {
Y* y=new Y();
y->f(new C);
}
I can't understand why this turns ambiguous and there are 2 candidates:
Y::f(B*)
Y::f(C*)
For an overloading function to be selected, it has to be the "best" at accepting each individual argument, including the implicit argument that becomes this. Best is defined in terms of the least conversions needed to convert the argument (in the caller) to the parameter (in the callee).
virtual void f(C*) const agrees perfectly with an argument of type C*, but the const qualifier at the end requires that this be converted from a non-const Y* to a Y const *. This is what the compiler is complaining about. If you cast
static_cast< Y const * >( y )->f(new C);
The problem goes away (although this isn't immediately illustrative since the extra qualification disqualifies the other overloads).
Note that all the overloads in X aren't even checked. The name resolution which finds all the overloads to be considered starts at the derived class and proceeds up the inheritance branches until it finds a matching name, and then it stops. To merge functions from multiple classes into one overload set, use a using declaration inside Y, using X::f;.
The actual solution to this problem is probably to introduce more matching overloads without const qualifiers at the end, so the const qualification of the calling pointer doesn't play such an unintuitive role.
Your overload for C is the only const member function.
y is non const and all overloads of f are acceptable, hence the call is ambiguous.
Ways to resolve the ambiguity:
Add a non const overload for C
Make y const
Make the overloads for A and B const
void f(C*) { std::cout << "X::f(C*)\n"; } in base class
is not visible due to name hiding.
use
using X::f;
in derived class, and it works as expected.
Maybe a silly question.
Suppose I have the following:
class A{
int x;
int y;
virtual int get_thing(){return x;}
};
class B : public A {
int get_think(){return y;}
};
In the example above, B::get_thing returns x because the overriding code has a typo.
How can I ensure, at compile time that the get_thing function has been overridden in class B so that it returns y?
Assuming A::get_thing is virtual, and assuming class B is derived from class A, and you have C++11 support, you can use the override special identifier:
class B : public A{
int get_think() override {return y;}
};
This would produce a compiler error. Note that this is based on the signature of the method, i.e. its name, cv qualifiers, and types of the parameters. The return type or the body of the function do not come into it.
First you have an error in your example, I think B supposed to be a child of A, isn't it?!
But answer is: you can compare address of functions( of course if you want it and can't check it in programming time ):
if( reinterpret_cast<void*>(&B::get_think) != reinterpret_cast<void*>(&A::get_think) ) {
std::cout << "B override A";
} else {
std::cout << "B override A";
}
#include <iostream>
class base
{
public:
virtual void print (int a)
{
std::cout << "a: " << a << " base\n";
}
virtual void print (int a, int b)
{
std::cout << "base\n";
}
};
class derived : public base
{
public:
virtual void print (double d)
{
std::cout << "derived\n";
}
};
int main ()
{
int i = 10;
double d = 10000.0;
base *b = new derived ();
b->print (i, i);
b->print (d);
return 0;
}
The output of this function is:
base
a: 10000 base
Why b->print (d) don't invoke the derived class implementation and
performs static cast on 'd' to provide a match with base class
implementation ?
What rule is applied here during virtual function lookup ?
derived::print does not override any member function in base. It is declared as having a single parameter of type double but the two virtual member functions named print in base are declared as having one and two parameters of type int.
When you use b->print(d), only member functions in base are considered during overload resolution, so only void base::print(int) and void base::print(int, int) are considered. void derived::print(double) can't be found because the compiler has no idea that b points to a derived object.
If derived were to override one of the two print functions declared as virtual member functions in base, then that override would be called at runtime.
(On a somewhat related note, derived::print hides the two base::print member functions, so if you were to try to use one of the base class print functions, e.g., derived().print(1, 1), it would fail. You would need to use a using declaration to make those member functions available during name lookup.)
Overload resolution happens at compile time. Overrides happen at run time.
Therefore, the overload resolution of b->print(d); happens first. This selects Base::print(int) because it's the only one-argument print.
At runtime, b points to a Derived object that has no override for Base::print(int). Therefore, Base::print(int) is still called.
Because double can be automatically converted to an int in the first definition it sees (in the base class)
See explicit keyword or this question