A
, B
, and C
be related to each other by inheritance.
Suppose each class's default constructor body contains a statement that prints
a message when when the constructor's called. If the declaration
B b;
produces the following output:
Hello from C::C(); Hello from A::A(); Hello from B::B();
describe the inheritance relations among the three classes.
Constructors are called from the top down; that is, a parent's constructor is called before the child's. The sequence of print statements given in the problem is consistent with the declarations
$ cat t.cc #includeusing std::cout; struct C { C() { cout << "Hello from C:C()\n"; } }; struct A : C { A() { cout << "Hello from A:A()\n"; } }; struct B : A { B() { cout << "Hello from B:B()\n"; } }; int main() { B b; } $ g++ -o t -ansi -pedantic -Wall t.cc t.cc: In function int main(): t.cc:20: warning: unused variable struct B b $ ./t Hello from C:C() Hello from A:A() Hello from B:B() $
struct A { virtual ~A() { } }; struct B : A { int i; };
or
struct A { }; struct B : A { virtual ~B() { } int i; };
is correct? Explain.
The parent's virtual destructor must be virtual; the declarations
struct A { virtual ~A() { } }; struct B : B { int i; };
are correct. The virtual keyword is not inherited up the hierarchy; the declarations
struct A { }; struct B : B { virtual ~B() { } int i; };
causes the compiler to use static-type lookup for A
's destructor, which is
not correct when a pointer or reference to A
is actually a pointer or
reference to B
.
#includestruct A { double val; }; struct B : A { int val; }; int main() { cout << "sizeof(A) = " << sizeof(A) << "\n"; cout << "sizeof(B) = " << sizeof(B) << "\n"; }
The idea being that because an integer is smaller than a double, than B
should be smaller than A
. However, you colleague was surprised when the
program produced the following output:
sizeof(A) = 8 sizeof(B) = 16
Ignoring the exact numbers produced, explain why B
is larger than A
and the error in your colleague's thinking.
B
is larger than A
because B
contains both the variables
val
. The error in your colleague's thinking most likely arises from the
belief that a redeclaration in the child replaces a declaration in the parent;
for example, the declaration int val
in the child replaces the declaration
double val
in the parent. However, a child's redeclaration only hides the
parent's declaration; the parent's declaration is still around, and you can use
the ::
scoping operator to get at it:
$ cat t.cc #includeusing std::cout; struct C { double val; C() : val(3.14) { } }; struct A : C { int val; A() : val(42) { } void print(void) { cout << "val = " << val << ", parent's val = " << C::val << "\n"; } }; int main() { A a; a.print(); } $ g++ -o t -ansi -pedantic -Wall t.cc $ ./t val = 42, parent's val = 3.14 $
A public: void f1(void); B public: void f1(void); void f2(void); non-public: void f3(void); C public: void f1(void); non-public: void f3(void);
Your class declarations should use inheritance to minimize the total number of member function definitions.
f1()
appears in all three classes, so its declaration should be in the
most ancestral of the parent classes. Class A contains only f1()
, so it
needs to be the parent of the other two classes.
f2()
appears in B
but not in C
, so C
needs to be the parent
of B
.
Finally, f3()
appears non-publicly in both B
and C
, which
means that f3()
should be protected in C
. A suitable set of
declarations would be
class A { public: void f1(void); }; class C : public A { protected: void f3(void); }; class B : public C { public: void f2(void); };
This page last modified on 19 December 2001.