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 ?"
Showing posts with label inheritance. Show all posts
Showing posts with label inheritance. Show all posts
Friday, February 03, 2006
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.
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'
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'
Subscribe to:
Posts (Atom)