C++ inheritance all frelled up!..

Started by
7 comments, last by Zahlman 17 years, 7 months ago
Why does this print "in fat b" versus "fat a"?

using namespace std;
class a
{
public:
	a();
	~a();
	virtual int fat(int x);
};

a::a()
{
	cout << "constructor a\n";
}

a::~a()
{
	cout << "destructor a\n";
}

int a::fat(int x)
{
	cout << "fat a\n";
	return 1;
}

class b : public a
{
public:
	b();
	~b();
	int fat(double y);
};

b::b()
{
	cout << "constructor b\n";
}

b::~b()
{
	cout << "destructor b\n";
}

int b::fat(double y)
{
	cout << "in fat b\n";	return 1;
}



int _tmain(int argc, _TCHAR* argv[])
{
	b me;

	me.fat((int) 1);

	return 0;
}
Advertisement
Different argument types.
virtual int fat(int x);int fat(double y);
"frelled" huh. I see.

Well the reason is one takes a double and one takes a float, so you actually aren't overloading via inheritence, you're doing plain old function overloading based on type. Because they take different parameters, they both exist at once.

If you cast it to a double, it would probably run fat a.

EDIT: Barius got there first, and was far more concise. [wink]
Anything posted is personal opinion which does not in anyway reflect or represent my employer. Any code and opinion is expressed “as is” and used at your own risk – it does not constitute a legal relationship of any kind.
You should use a virtual destructor for a. Otherwise this won't work right:

a* x = new b;
delete x;

it would only call a's destructor, not b's even though the object is of type b.
You guys missed the point:

Quote:
Why does this print "in fat b" versus "fat a"?


The function int fat(double y); in b hides the function virtual int fat(int x); in a, so when you call fat on an object of type b, only the functio ntaking a double is visiable, so the int gets converted to a double.

To have this work you need to change the declaration of b to:
class b : public a{public:	b();	~b();	int fat(double y);        using a::fat;//make a::fat visible here.};
Quote:Original post by Nitage
You guys missed the point:

Quote:
Why does this print "in fat b" versus "fat a"?


The function int fat(double y); in b hides the function virtual int fat(int x); in a, so when you call fat on an object of type b, only the functio ntaking a double is visiable, so the int gets converted to a double.

To have this work you need to change the declaration of b to:
*** Source Snippet Removed ***


Err no it doesn't, the functions have different signatures

me.fat((double) 1); // calls fat a
Anything posted is personal opinion which does not in anyway reflect or represent my employer. Any code and opinion is expressed “as is” and used at your own risk – it does not constitute a legal relationship of any kind.
Quote:Original post by paulecoyote
Err no it doesn't, the functions have different signatures


Umm, yes it does. Read the holy standard.

Despite casting the argument to an int, it gets reconverted back to a double because the fat() function in class b hoides the fat() function in class a. If the OP added a "using a::fat" in his class b definition, the class a fat() would be hoisted into class b.

Stephen M. Webb
Professional Free Software Developer

alrighty, hands up, I was wrong on that. [rolleyes]

You know, in over 8 years of C++ I've never had to use the using keyword like that in any of my class structures. I've used it with namespaces, but not to force declare things in class scope.

EDIT:
Although I think I might have used it to fudge something when writing a template actually come to think of it.


Learn something new everyday I guess.

It seems kind of messy to me, like something you could do, but not necessarily should do.



From MSDN

The using declaration introduces a name into the declarative region in which the using declaration appears.


using [typename][::] nested-name-specifier unqualified-idusing :: unqualified-id



Remarks
The name becomes a synonym for an entity declared elsewhere. It allows an individual name from a specific namespace to be used without explicit qualification. This is in contrast to the using directive, which allows all the names in a namespace to be used without qualification. See using Directive for more information.

Example
A using declaration can be used in a class definition.

// using_declaration1.cpp#include <stdio.h>class B {public:   void f(char) {      printf_s("In B::f()\n");   }   void g(char) {      printf_s("In B::g()\n");   }};class D : B {public:   using B::f;   using B::g;   void f(int) {      printf_s("In D::f()\n");      f('c');   }   void g(int) {      printf_s("In D::g()\n");      g('c');   }};int main() {   D myD;   myD.f(1);   myD.g('a');}



Output

In D::f()
In B::f()
In B::g()


When used to declare a member, a using declaration must refer to a member of a base class.

// using_declaration2.cpp#include <stdio.h>class B {public:   void f(char) {      printf_s("In B::f()\n");   }   void g(char) {      printf_s("In B::g()\n");   }};class C {public:   int g();};class D2 : public B {public:   using B::f;   // ok: B is a base of D2   // using C::g;   // error: C isn't a base of D2};int main() {   D2 MyD2;   MyD2.f('a');}


Output

In B::f()


Members declared with a using declaration can be referenced using explicit qualification. The :: prefix refers to the global namespace.

// using_declaration3.cpp#include <stdio.h>void f() {   printf_s("In f\n");}namespace A {   void g() {      printf_s("In A::g\n");   }}namespace X {   using ::f;   // global f   using A::g;   // A's g}void h() {   printf_s("In h\n");   X::f();   // calls ::f   X::g();   // calls A::g}int main() {   h();}


Output

In h
In f
In A::g


When a using declaration is made, the synonym created by the declaration refers only to definitions that are valid at the point of the using declaration. Definitions added to a namespace after the using declaration are not valid synonyms.

A name defined by a using declaration is an alias for its original name. It does not affect the type, linkage or other attributes of the original declaration.

// post_declaration_namespace_additions.cpp// compile with: /cnamespace A {   void f(int) {}}using A::f;   // f is a synonym for A::f(int) onlynamespace A {   void f(char) {}}void f() {   f('a');   // refers to A::f(int), even though A::f(char) exists}void b() {   using A::f;   // refers to A::f(int) AND A::f(char)   f('a');   // calls A::f(char);}


With respect to functions in namespaces, if a set of local declarations and using declarations for a single name are given in a declarative region, they must all refer to the same entity, or they must all refer to functions.

// functions_in_namespaces1.cpp// C2874 expectednamespace B {    int i;    void f(int);    void f(double);}void g() {    int i;    using B::i;   // error: i declared twice    void f(char);    using B::f;   // ok: each f is a function}


In the example above, the using B::i statement causes a second int i to be declared in the g() function. The using B::f statement does not conflict with the f(char) function because the function names introduced by B::f have different parameter types.

A local function declaration cannot have the same name and type as a function introduced by using declaration. For example:

// functions_in_namespaces2.cpp// C2668 expectednamespace B {    void f(int);    void f(double);}namespace C {    void f(int);    void f(double);    void f(char);}void h() {    using B::f;          // introduces B::f(int) and B::f(double)    using C::f;          // C::f(int), C::f(double), and C::f(char)    f('h');              // calls C::f(char)    f(1);                // C2668 ambiguous: B::f(int) or C::f(int)?    void f(int);         // C2883 conflicts with B::f(int) and C::f(int)}


With respect to inheritance, when a using declaration introduces a name from a base class into a derived class scope, member functions in the derived class override virtual member functions with the same name and argument types in the base class.

// using_declaration_inheritance1.cpp#include <stdio.h>struct B {   virtual void f(int) {      printf_s("In B::f(int)\n");   }   virtual void f(char) {      printf_s("In B::f(char)\n");   }   void g(int) {      printf_s("In B::g\n");   }   void h(int);};struct D : B {   using B::f;   void f(int) {   // ok: D::f(int) overrides B::f(int)      printf_s("In D::f(int)\n");   }   using B::g;   void g(char) {   // ok: there is no B::g(char)      printf_s("In D::g(char)\n");   }   using B::h;   void h(int) {}   // Note: D::h(int) hides non-virtual B::h(int)};void f(D* pd) {   pd->f(1);   // calls D::f(int)   pd->f('a');   // calls B::f(char)   pd->g(1);   // calls B::g(int)   pd->g('a');   // calls D::g(char)}int main() {   D * myd = new D();   f(myd);}


Output

In D::f(int)
In B::f(char)
In B::g
In D::g(char)


All instances of a name mentioned in a using declaration must be accessible. In particular, if a derived class uses a using declaration to access a member of a base class, the member name must be accessible. If the name is that of an overloaded member function, then all functions named must be accessible.

See Member-Access Control, for more information on accessibility of members.

// using_declaration_inheritance2.cpp// C2876 expectedclass A {private:   void f(char);public:   void f(int);protected:   void g();};class B : public A {   using A::f;   // C2876: A::f(char) is inaccessiblepublic:   using A::g;   // B::g is a public synonym for A::g}; 

Anything posted is personal opinion which does not in anyway reflect or represent my employer. Any code and opinion is expressed “as is” and used at your own risk – it does not constitute a legal relationship of any kind.
Quote:Original post by paulecoyote
alrighty, hands up, I was wrong on that. [rolleyes]

You know, in over 8 years of C++ I've never had to use the using keyword like that in any of my class structures. I've used it with namespaces, but not to force declare things in class scope.


That's because sane people don't usually end up creating this situation for themselves. Seriously - if bs can fat() with doubles as well as they do with ints, why shouldn't any other as be able to do so? Derived-class-specific functionality normally demands a new function name.

This topic is closed to new replies.

Advertisement