Showing posts with label inheritance. Show all posts
Showing posts with label inheritance. Show all posts

Friday, February 03, 2006

name hidding again

the name hidding seems to be pretty compiler specific unfortunately.
for example:
struct A
{
int x;
};

struct B: A
{
int x;
};

struct C: A, B
{
void f() { x = 0; }
};

int main()
{
C i;
i.f();
}
here
http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=/com.ibm.xlcpp8a.doc/language/ref/cplr138.htm

it says that "The assignment x = 0 in function C::f() is not ambiguous because the declaration B::x has hidden A::x."

when i see this I was confused, what the hell; indeed, B::x hiddens A::x but since i is of C type, both B::x and A::x are available to C.
i just put this code in Visual C++ 2003 and it gives (of course) the compile error:

e:\Projects\test2\test2\test2.cpp(15): error C2385: ambiguous access of 'x' in 'C' could be the 'x' in base 'A::x' or the 'x' in base 'B::x'

now, i bet that there are many things like this, compiler specific (the C++ ref from the link is for the IBM compiler);
and this makes life harder.

on the next interview, you can be very smart and write that this code works OK; if you get a mocking smile, you can ask politely "do you have an IBM C compiler ?"

dominance

there is a thing called name dominance in C++. consider this:

class A
{
public:
int f() { printf("\nA::f()"); return 1; }
};

class B : virtual public A
{
public:
void f() { printf("\nB::f()"); } // hides the int A::f()
};

class C : virtual public A
{
};

class D : public B, public C
{

};

the hierarchy is this:

A
B C
D

and D has only one copy of A in memory (beacuse B and C inherits virtual from A)
now:

D d;
d.f();

f() is not ambigous because void B::f() hides int A::f().
d.f() will get B:f() called because D derives from B which hides the A::f().
Note that this is not ambigous beacause the A is virtual inherited in B and C and this makes that the d object to contain only one instance of A within it. if, for example, B or C will not have virtual inherited from A (either one of them or both) this will mean that d will have 2 A objects within it.

now, consider this case:

C *d = new D;
d->f();

d->f() will get A:f() called.
Why is that stays in the mechanism of calling a function.
in the first case, when d is a D object:
D d;
when you call
d.f();
the function which is get called is determined at compile time; the function called is the D::f()

in the 2nd case, when
C *d = new D;
when you call
d->f();
the object d is really a D object but since the function called is not virtual (not taken from the vtable) the function called is from C object scope, which is A::f(), beacuse C inherits A::f().

hence, the rule is this:
if the function called is not virtual, the function called is the one from the type of the object type.

public inheritance broken

consider this:

class A
{
public:
void f();
void f(int x);
}

class B : public A
{
public:
void f(); // hides all A::f() overloads
}

you have an object
B b;
and you want to call the f(int x)
b.f(1);

normally you would think that since B inherits A, it inherits all the A functions, which is true, but not when for overloading.
the name f() declared in B class will override any base names. this includes the following case:

class A1
{
public:
void f();
}

class B1 : public A1
{
public:
int f; // hides all A1 'f'names
}

if you try to write the call:
b1.f();
you will get a compile error

as within a class, the names in a inheritance tree shoule be unique;

if you want to preserve the is-a relationship(a derived class should access all public inherited base class functionality) then you need to declare in the derived class the base functions by using 'using' declarator:

class B : public A
{public:
void f(); // hides all A 'f'names
using A::f; //OK, now we have the A::f(int x) within the B
}

b.f(1);

Note that 'using' works for the seeing in derived classes the overloads, it will not work for the 2nd case, when the base class is hiding a base class function by a member variale (because its not possible to have within the same class B 2 names f() and int f)

this is a problem described in Effective C++. Item 33. 'Avoid hiding inherited names'