Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
B.Eckel - Thinking in C++, Vol.2, 2nd edition.pdf
Скачиваний:
50
Добавлен:
08.05.2013
Размер:
2.09 Mб
Скачать

int main() { MBase b;

WRITE(sizeof(b));

NonVirtualInheritance nonv_inheritance; WRITE(sizeof(nonv_inheritance)); VirtualInheritance v_inheritance; WRITE(sizeof(v_inheritance));

MI mi; WRITE(sizeof(mi));

} ///:~

Each of these classes only contains a single byte, and the “core size” is that byte. Because all these classes contain virtual functions, you expect the object size to be bigger than the core size by a pointer (at least – your compiler may also pad extra bytes into an object for alignment). The results are a bit surprising (these are from one particular compiler; yours may do it differently):

sizeof(b) = 2 sizeof(nonv_inheritance) = 2 sizeof(v_inheritance) = 6 sizeof(MI) = 12

Both b and nonv_inheritance contain the extra pointer, as expected. But when virtual inheritance is added, it would appear that the VPTR plus two extra pointers are added! By the time the multiple inheritance is performed, the object appears to contain five extra pointers (however, one of these is probably a second VPTR for the second multiply inherited subobject).

The curious can certainly probe into your particular implementation and look at the assembly language for member selection to determine exactly what these extra bytes are for, and the

cost of member selection with multiple inheritance19. The rest of you have probably seen enough to guess that quite a bit more goes on with virtual multiple inheritance, so it should be used sparingly (or avoided) when efficiency is an issue.

Upcasting

When you embed subobjects of a class inside a new class, whether you do it by creating member objects or through inheritance, each subobject is placed within the new object by the compiler. Of course, each subobject has its own this pointer, and as long as you’re dealing with member objects, everything is quite straightforward. But as soon as multiple inheritance

19 See also Jan Gray, “C++ Under the Hood”, a chapter in Black Belt C++ (edited by Bruce Eckel, M&T Press, 1995).

Chapter 15: Multiple Inheritance

352

is introduced, a funny thing occurs: An object can have more than one this pointer because the object represents more than one type during upcasting. The following example demonstrates this point:

//: C06:Mithis.cpp

// MI and the "this" pointer #include <fstream>

using namespace std; ofstream out("mithis.out");

class Base1 { char c[0x10];

public:

void printthis1() {

out << "Base1 this = " << this << endl;

}

};

class Base2 { char c[0x10];

public:

void printthis2() {

out << "Base2 this = " << this << endl;

}

};

class Member1 { char c[0x10];

public:

void printthism1() {

out << "Member1 this = " << this << endl;

}

};

class Member2 { char c[0x10];

public:

void printthism2() {

out << "Member2 this = " << this << endl;

}

};

class MI : public Base1, public Base2 { Member1 m1;

Chapter 15: Multiple Inheritance

353

Member2 m2; public:

void printthis() {

out << "MI this = " << this << endl; printthis1();

printthis2();

m1.printthism1();

m2.printthism2();

}

};

int main() { MI mi;

out << "sizeof(mi) = "

<< hex << sizeof(mi) << " hex" << endl; mi.printthis();

// A second demonstration: Base1* b1 = &mi; // Upcast Base2* b2 = &mi; // Upcast

out << "Base 1 pointer = " << b1 << endl; out << "Base 2 pointer = " << b2 << endl;

} ///:~

The arrays of bytes inside each class are created with hexadecimal sizes, so the output addresses (which are printed in hex) are easy to read. Each class has a function that prints its this pointer, and these classes are assembled with both multiple inheritance and composition into the class MI, which prints its own address and the addresses of all the other subobjects. This function is called in main( ). You can clearly see that you get two different this pointers for the same object. The address of the MI object is taken and upcast to the two different types. Here’s the output:20

sizeof(mi) = 40 hex mi this = 0x223e Base1 this = 0x223e Base2 this = 0x224e Member1 this = 0x225e Member2 this = 0x226e

Base 1 pointer = 0x223e Base 2 pointer = 0x224e

20 For easy readability the code was generated for a small-model Intel processor.

Chapter 15: Multiple Inheritance

354

Соседние файлы в предмете Численные методы
  • #
    08.05.20133.99 Mб22A.Menezes, P.van Oorschot,S.Vanstone - HANDBOOK OF APPLIED CRYPTOGRAPHY.djvu
  • #
  • #
    08.05.20135.91 Mб24B.Eckel - Thinking in Java, 3rd edition (beta).pdf
  • #
  • #
    08.05.20136.09 Mб17D.MacKay - Information Theory, Inference, and Learning Algorithms.djvu
  • #
    08.05.20133.85 Mб15DIGITAL Visual Fortran ver.5.0 - Programmers Guide to Fortran.djvu
  • #
    08.05.20131.84 Mб12E.A.Lee, P.Varaiya - Structure and Interpretation of Signals and Systems.djvu