Sign in to follow this  

C++ inheritance all frelled up!..

This topic is 4113 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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;
}

Share this post


Link to post
Share on other sites
"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]

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
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.

Share this post


Link to post
Share on other sites
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.

};

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.



[quote]From MSDN

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



using [typename][::] nested-name-specifier unqualified-id
using :: 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: /c
namespace A {
void f(int) {}
}

using A::f; // f is a synonym for A::f(int) only

namespace 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 expected
namespace 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 expected
namespace 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 expected
class A {
private:
void f(char);
public:
void f(int);
protected:
void g();
};

class B : public A {
using A::f; // C2876: A::f(char) is inaccessible
public:
using A::g; // B::g is a public synonym for A::g
};








[/quote]

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites

This topic is 4113 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this