SlideShare uma empresa Scribd logo
1 de 21
C++ : наследование, часть 3 Дмитрий Штилерман, Рексофт
Краткое содержание ,[object Object],[object Object],[object Object],[object Object],[object Object]
Начало: отвратительный пример ,[object Object],[object Object]
Множественное наследование: что есть концептуально нового? ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]
Множественные классификации ,[object Object],[object Object],[object Object],[object Object]
Множественное положение в одной классификации - «кровосмешение» ,[object Object],[object Object],[object Object],[object Object]
Реализация множественного наследования в C++ : подобъекты class B1  {int m_b1;}; class B2  {int m_b2;}; class D : B1, B2  {int m_d;}; ,[object Object],[object Object]
Реализация множественного наследования в C++ : преобразование типов (1) class B1  {   int m_b1;   int f1()   {return m_b1;}  }; class B2  {   int m_b2;   int f2()   {return m_b2;}   }; class D : B1, B2  {   int m_d;   int g()   {return m_d+f1()+f2();}   }; Что сгенерирует компилятор? int B1::f1(B1* this)  {return this->m_b1;} int B2::f2(B2* this)  {return this->m_b2;} int D::g(D* this)  {   return this->m_d +    B1::f1( (B1*)this ) +   B2::f2( (B2*)this );  }  Подобъекты  B1  и  B2  лежат по разным адресам. Как компилятор реализует преобразования  (B1*)this  и ( B2*)this?
Реализация множественного наследования в C++ : преобразование типов (2) int D::delta_B1()  {return 0;} int D::delta_B2()  {return sizeof(B1);} int D::g(D* this)  {   return this->m_d +    B1::f1(this+delta_B1()) +   B2::f2(this+delta_B2());  } Вводятся псевдофункции  D::delta_B1()  и  D::delta_b2() . NB:  ниже вся арифметика указателей производится в байтах (не  C ).
«Ромб наследования» Если буквально следовать описанной выше схеме, объект  D  будет содержать два подобъекта  A. Как тогда реализовывать приведение  (A*)pD ( например, для вызова методов  A)?!
«Ромб наследования»: неоднозначность при обычном (невиртуальном) наследовании class A  {   int m_a;   int f() {return m_a;}  }; class B : A {}; class C : A {}; class D : B, C  {   int g()   {return B::f()+C::f();}  }; Что сгенерирует компилятор? int A::f(A* this)  {return this->m_a;} int D::g(D* this)  {   return   A::f(this + D::delta_B() + B::delta_A())   +   A::f(this + D::delta_C() + C::delta_A());   } // В нашем случае обе  delta_A  равны 0 В контексте класса  D  любые имена из  A  должны явно квалифицироваться именем того или другого базового класса  D (B  или  C). Без этого компилятор не сможет понять, какой из подобъектов A  имеется в виду.
«Ромб наследования»: виртуальное наследование Бывают случаи, когда описанная неоднозначность классификации недопустима. Естественное решение: потребовать от компилятора, чтобы производные классы всегда содержали ровно один подобъект класса  A. Виртуальное наследование class A {…}; class B : virtual A {…}; class C : virtual A {…}; class D : B, C {…}; Важно: виртуальнсть наследования описывается в контексте  производных  классов ( B, C) , а не в контексте  базового  класса ( A) !
Реализация виртуального наследования: проблема  размещения подобъектов  (1) class A  {   int m_a;   int f_a() {return m_a;}  }; class B : virtual A  {   int f_b() {return f_a();}   }; class C : virtual A  {   int f_c() {return f_a();}   }; class D : B, C  {   int f_d()   {return f_a()+f_b()+f_c();}  }; Что сгенерирует компилятор? int B::f_b(B* this)  {return A::f_a(this+B::delta_A());} int C::f_c(C* this)  {return A::f_a(this+C::delta_A());} int D::f_d(D* this)  {   return A::f_a(this+D::delta_A()) +   B::f_b(this+D::delta_B()) +   C::f_c(this+D::delta_C());  }  Проблема:  B::delta_A()  и  C::delta_A() должны быть разными в случае, если most derived object относится к классу D  или классам  B / C!
Реализация виртуального наследования: проблема  размещения подобъектов  (2) ,[object Object],[object Object],[object Object]
Реализация виртуального наследования: проблема  конструирования подобъектов  (1) class A  {   int m_a;   A() {m_a = 0;}  }; class B : virtual A  {   B() {}  }; class C : virtual A  {   C() {}   }; class D : B, C  {   D() {}  }; При конструировании объекта должны конструироваться подобъекты его баз? Что сгенерирует компилятор? Наивный вариант: A::A(A* this) {this->m_a = 0;} B::B(B* this) {A::A(this+B::delta_A());} C::C(C* this) {C::C(this+C::delta_A());} D::D(D* this)  {   B::B(this+D::delta_B());    C::C(this+D::delta_C());  } Проблема: в таком варианте конструктор для подобъекта  A  будет вызван два раза !
Реализация виртуального наследования: проблема  конструирования подобъектов  (2) ,[object Object],[object Object],[object Object],[object Object],[object Object]
Реализация виртуального наследования: проблема  конструирования подобъектов  (3) class A  {   int m_a;   A() {m_a = 0;}  }; class B : virtual A  {B(){}}; class C : virtual A  {C(){}}; class D : B, C  {D(){}}; void test()  {   B b;   C c;   D d;  } A::A(A* this) {this->m_a = 0;} B::B(B* this, bool bMostDerived)  {   if(bMostDerived)   A::A(this+B::delta_A());  } // То же для  C… D::D(D* this, bool bMostDerived)  {   if(bMostDerived)   A::A(this+D::delta_A());   B::B(this+D::delta_B(), false);    C::C(this+D::delta_C(), false);  } void test()  {   B b; B::B(&b, true);   //  То же для  C…   D d; D::D(&d, true);  }
Реализация множественного и виртуального наследования:  другие проблемы ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]
Виртуальное наследование: основной концептуальный конфликт ,[object Object],[object Object]
Виртуальное наследование: основное правило применения ,[object Object],[object Object],[object Object]
Специальный трюк: закрытое виртуальное наследование  Задача: мы хотим, чтобы базовый класс   мог бы «настраиваться» на каждый свой производный класс с помощью некоторых данных, специфичных для этого производного класса. // Файл  Gadget.h class GadgetData {…}; class GadgetBase  {   protected:   GadgetData m_GadgetData;    GadgetBase(const GadgetData& x)   {m_GadgetData = x;}  }; class Gadget :   private virtual GadgetBase  {…}; // Файл  FunnyGadget.h #include “Gadget.h” class FunnyGadget :   public Gadget  {   static GadgetData s_FunnyData;   public:   SpecialGadget() :   GadgetBase(s_FunnyData)   {}   };

Mais conteúdo relacionado

Mais procurados

Составление семантического ядра. Бурж vs рунет
Составление семантического ядра. Бурж vs рунетСоставление семантического ядра. Бурж vs рунет
Составление семантического ядра. Бурж vs рунетcollaborator.pro
 
В.С.Крикоров-Единый Космос 2
В.С.Крикоров-Единый Космос 2В.С.Крикоров-Единый Космос 2
В.С.Крикоров-Единый Космос 2Yury Podusov
 
Как выбрать нишу для сайта вебмастеру для заработка
Как выбрать нишу для сайта вебмастеру для заработкаКак выбрать нишу для сайта вебмастеру для заработка
Как выбрать нишу для сайта вебмастеру для заработкаcollaborator.pro
 
В.С.Крикоров-Единый Космос 5
В.С.Крикоров-Единый Космос 5В.С.Крикоров-Единый Космос 5
В.С.Крикоров-Единый Космос 5Yury Podusov
 
Үйлдвэрлэлийн зардал-1а /тогтмол болон хувьсах зардал гэх мэт.../
Үйлдвэрлэлийн зардал-1а /тогтмол болон хувьсах зардал гэх мэт.../ Үйлдвэрлэлийн зардал-1а /тогтмол болон хувьсах зардал гэх мэт.../
Үйлдвэрлэлийн зардал-1а /тогтмол болон хувьсах зардал гэх мэт.../ Adilbishiin Gelegjamts
 
îïèñàíèå
îïèñàíèåîïèñàíèå
îïèñàíèåguest2dbab6
 
Amplifying Reduction Non Approx
Amplifying Reduction Non ApproxAmplifying Reduction Non Approx
Amplifying Reduction Non ApproxStas Fomin
 
Derandomization Luby
Derandomization LubyDerandomization Luby
Derandomization LubyStas Fomin
 
Эрэлт, нийлүүлэлтийн мэдрэмж /орлогын мэдрэмж, солбисон мэдрэмж/
Эрэлт, нийлүүлэлтийн мэдрэмж /орлогын мэдрэмж, солбисон мэдрэмж/ Эрэлт, нийлүүлэлтийн мэдрэмж /орлогын мэдрэмж, солбисон мэдрэмж/
Эрэлт, нийлүүлэлтийн мэдрэмж /орлогын мэдрэмж, солбисон мэдрэмж/ Adilbishiin Gelegjamts
 
Хэрэглэгчийн сонголт
Хэрэглэгчийн сонголт Хэрэглэгчийн сонголт
Хэрэглэгчийн сонголт Adilbishiin Gelegjamts
 
Automatic Build Of Semantic Translational Dictionary
Automatic Build Of Semantic Translational DictionaryAutomatic Build Of Semantic Translational Dictionary
Automatic Build Of Semantic Translational DictionaryDmitry Kan
 
Algorithms Dtime Dspace
Algorithms Dtime DspaceAlgorithms Dtime Dspace
Algorithms Dtime DspaceStas Fomin
 
Бие даалтын стандарт
Бие даалтын стандартБие даалтын стандарт
Бие даалтын стандартAdilbishiin Gelegjamts
 
Aleksei petrov-vizualizacija-v-zabbix-final
Aleksei petrov-vizualizacija-v-zabbix-finalAleksei petrov-vizualizacija-v-zabbix-final
Aleksei petrov-vizualizacija-v-zabbix-finalMichael Ganschuk
 
МӨНГӨ, МӨНГӨНИЙ ТҮҮХ /мөнгөний үүсэл хөгжил, зоос, цаасан мөнгө гэх мэт/
МӨНГӨ, МӨНГӨНИЙ ТҮҮХ /мөнгөний үүсэл хөгжил, зоос, цаасан мөнгө гэх мэт/МӨНГӨ, МӨНГӨНИЙ ТҮҮХ /мөнгөний үүсэл хөгжил, зоос, цаасан мөнгө гэх мэт/
МӨНГӨ, МӨНГӨНИЙ ТҮҮХ /мөнгөний үүсэл хөгжил, зоос, цаасан мөнгө гэх мэт/Adilbishiin Gelegjamts
 

Mais procurados (19)

Составление семантического ядра. Бурж vs рунет
Составление семантического ядра. Бурж vs рунетСоставление семантического ядра. Бурж vs рунет
Составление семантического ядра. Бурж vs рунет
 
В.С.Крикоров-Единый Космос 2
В.С.Крикоров-Единый Космос 2В.С.Крикоров-Единый Космос 2
В.С.Крикоров-Единый Космос 2
 
Как выбрать нишу для сайта вебмастеру для заработка
Как выбрать нишу для сайта вебмастеру для заработкаКак выбрать нишу для сайта вебмастеру для заработка
Как выбрать нишу для сайта вебмастеру для заработка
 
В.С.Крикоров-Единый Космос 5
В.С.Крикоров-Единый Космос 5В.С.Крикоров-Единый Космос 5
В.С.Крикоров-Единый Космос 5
 
Item 4.2 Moldova SDG 6
Item 4.2 Moldova SDG 6Item 4.2 Moldova SDG 6
Item 4.2 Moldova SDG 6
 
Үйлдвэрлэлийн зардал-1а /тогтмол болон хувьсах зардал гэх мэт.../
Үйлдвэрлэлийн зардал-1а /тогтмол болон хувьсах зардал гэх мэт.../ Үйлдвэрлэлийн зардал-1а /тогтмол болон хувьсах зардал гэх мэт.../
Үйлдвэрлэлийн зардал-1а /тогтмол болон хувьсах зардал гэх мэт.../
 
Хэрэглэгчийн эрэлт
Хэрэглэгчийн эрэлт Хэрэглэгчийн эрэлт
Хэрэглэгчийн эрэлт
 
îïèñàíèå
îïèñàíèåîïèñàíèå
îïèñàíèå
 
анкета
анкетаанкета
анкета
 
Amplifying Reduction Non Approx
Amplifying Reduction Non ApproxAmplifying Reduction Non Approx
Amplifying Reduction Non Approx
 
Derandomization Luby
Derandomization LubyDerandomization Luby
Derandomization Luby
 
Эрэлт, нийлүүлэлтийн мэдрэмж /орлогын мэдрэмж, солбисон мэдрэмж/
Эрэлт, нийлүүлэлтийн мэдрэмж /орлогын мэдрэмж, солбисон мэдрэмж/ Эрэлт, нийлүүлэлтийн мэдрэмж /орлогын мэдрэмж, солбисон мэдрэмж/
Эрэлт, нийлүүлэлтийн мэдрэмж /орлогын мэдрэмж, солбисон мэдрэмж/
 
Хэрэглэгчийн сонголт
Хэрэглэгчийн сонголт Хэрэглэгчийн сонголт
Хэрэглэгчийн сонголт
 
Automatic Build Of Semantic Translational Dictionary
Automatic Build Of Semantic Translational DictionaryAutomatic Build Of Semantic Translational Dictionary
Automatic Build Of Semantic Translational Dictionary
 
Algorithms Dtime Dspace
Algorithms Dtime DspaceAlgorithms Dtime Dspace
Algorithms Dtime Dspace
 
Бие даалтын стандарт
Бие даалтын стандартБие даалтын стандарт
Бие даалтын стандарт
 
03
0303
03
 
Aleksei petrov-vizualizacija-v-zabbix-final
Aleksei petrov-vizualizacija-v-zabbix-finalAleksei petrov-vizualizacija-v-zabbix-final
Aleksei petrov-vizualizacija-v-zabbix-final
 
МӨНГӨ, МӨНГӨНИЙ ТҮҮХ /мөнгөний үүсэл хөгжил, зоос, цаасан мөнгө гэх мэт/
МӨНГӨ, МӨНГӨНИЙ ТҮҮХ /мөнгөний үүсэл хөгжил, зоос, цаасан мөнгө гэх мэт/МӨНГӨ, МӨНГӨНИЙ ТҮҮХ /мөнгөний үүсэл хөгжил, зоос, цаасан мөнгө гэх мэт/
МӨНГӨ, МӨНГӨНИЙ ТҮҮХ /мөнгөний үүсэл хөгжил, зоос, цаасан мөнгө гэх мэт/
 

Mais de Dmitry Stillermann

Как расти самому, помогая расти другим — практическое применение Management T...
Как расти самому, помогая расти другим — практическое применение Management T...Как расти самому, помогая расти другим — практическое применение Management T...
Как расти самому, помогая расти другим — практическое применение Management T...Dmitry Stillermann
 
OO Design with C++: 5. Design Principles, part 2
OO Design with C++: 5. Design Principles, part 2OO Design with C++: 5. Design Principles, part 2
OO Design with C++: 5. Design Principles, part 2Dmitry Stillermann
 
OO Design with C++: 2. Inheritance, part 2
OO Design with C++: 2. Inheritance, part 2OO Design with C++: 2. Inheritance, part 2
OO Design with C++: 2. Inheritance, part 2Dmitry Stillermann
 
OO Design with C++: 1. Inheritance, part 1
OO Design with C++: 1. Inheritance, part 1OO Design with C++: 1. Inheritance, part 1
OO Design with C++: 1. Inheritance, part 1Dmitry Stillermann
 

Mais de Dmitry Stillermann (6)

DiSC Model in Practice
DiSC Model in PracticeDiSC Model in Practice
DiSC Model in Practice
 
Как расти самому, помогая расти другим — практическое применение Management T...
Как расти самому, помогая расти другим — практическое применение Management T...Как расти самому, помогая расти другим — практическое применение Management T...
Как расти самому, помогая расти другим — практическое применение Management T...
 
OO Design with C++: 5. Design Principles, part 2
OO Design with C++: 5. Design Principles, part 2OO Design with C++: 5. Design Principles, part 2
OO Design with C++: 5. Design Principles, part 2
 
OO Design with C++: 2. Inheritance, part 2
OO Design with C++: 2. Inheritance, part 2OO Design with C++: 2. Inheritance, part 2
OO Design with C++: 2. Inheritance, part 2
 
OO Design with C++: 1. Inheritance, part 1
OO Design with C++: 1. Inheritance, part 1OO Design with C++: 1. Inheritance, part 1
OO Design with C++: 1. Inheritance, part 1
 
OO Design with C++: 0. Intro
OO Design with C++: 0. IntroOO Design with C++: 0. Intro
OO Design with C++: 0. Intro
 

OO Design with C++: 3. Inheritance, part 3

  • 1. C++ : наследование, часть 3 Дмитрий Штилерман, Рексофт
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8. Реализация множественного наследования в C++ : преобразование типов (1) class B1 { int m_b1; int f1() {return m_b1;} }; class B2 { int m_b2; int f2() {return m_b2;} }; class D : B1, B2 { int m_d; int g() {return m_d+f1()+f2();} }; Что сгенерирует компилятор? int B1::f1(B1* this) {return this->m_b1;} int B2::f2(B2* this) {return this->m_b2;} int D::g(D* this) { return this->m_d + B1::f1( (B1*)this ) + B2::f2( (B2*)this ); } Подобъекты B1 и B2 лежат по разным адресам. Как компилятор реализует преобразования (B1*)this и ( B2*)this?
  • 9. Реализация множественного наследования в C++ : преобразование типов (2) int D::delta_B1() {return 0;} int D::delta_B2() {return sizeof(B1);} int D::g(D* this) { return this->m_d + B1::f1(this+delta_B1()) + B2::f2(this+delta_B2()); } Вводятся псевдофункции D::delta_B1() и D::delta_b2() . NB: ниже вся арифметика указателей производится в байтах (не C ).
  • 10. «Ромб наследования» Если буквально следовать описанной выше схеме, объект D будет содержать два подобъекта A. Как тогда реализовывать приведение (A*)pD ( например, для вызова методов A)?!
  • 11. «Ромб наследования»: неоднозначность при обычном (невиртуальном) наследовании class A { int m_a; int f() {return m_a;} }; class B : A {}; class C : A {}; class D : B, C { int g() {return B::f()+C::f();} }; Что сгенерирует компилятор? int A::f(A* this) {return this->m_a;} int D::g(D* this) { return A::f(this + D::delta_B() + B::delta_A()) + A::f(this + D::delta_C() + C::delta_A()); } // В нашем случае обе delta_A равны 0 В контексте класса D любые имена из A должны явно квалифицироваться именем того или другого базового класса D (B или C). Без этого компилятор не сможет понять, какой из подобъектов A имеется в виду.
  • 12. «Ромб наследования»: виртуальное наследование Бывают случаи, когда описанная неоднозначность классификации недопустима. Естественное решение: потребовать от компилятора, чтобы производные классы всегда содержали ровно один подобъект класса A. Виртуальное наследование class A {…}; class B : virtual A {…}; class C : virtual A {…}; class D : B, C {…}; Важно: виртуальнсть наследования описывается в контексте производных классов ( B, C) , а не в контексте базового класса ( A) !
  • 13. Реализация виртуального наследования: проблема размещения подобъектов (1) class A { int m_a; int f_a() {return m_a;} }; class B : virtual A { int f_b() {return f_a();} }; class C : virtual A { int f_c() {return f_a();} }; class D : B, C { int f_d() {return f_a()+f_b()+f_c();} }; Что сгенерирует компилятор? int B::f_b(B* this) {return A::f_a(this+B::delta_A());} int C::f_c(C* this) {return A::f_a(this+C::delta_A());} int D::f_d(D* this) { return A::f_a(this+D::delta_A()) + B::f_b(this+D::delta_B()) + C::f_c(this+D::delta_C()); } Проблема: B::delta_A() и C::delta_A() должны быть разными в случае, если most derived object относится к классу D или классам B / C!
  • 14.
  • 15. Реализация виртуального наследования: проблема конструирования подобъектов (1) class A { int m_a; A() {m_a = 0;} }; class B : virtual A { B() {} }; class C : virtual A { C() {} }; class D : B, C { D() {} }; При конструировании объекта должны конструироваться подобъекты его баз? Что сгенерирует компилятор? Наивный вариант: A::A(A* this) {this->m_a = 0;} B::B(B* this) {A::A(this+B::delta_A());} C::C(C* this) {C::C(this+C::delta_A());} D::D(D* this) { B::B(this+D::delta_B()); C::C(this+D::delta_C()); } Проблема: в таком варианте конструктор для подобъекта A будет вызван два раза !
  • 16.
  • 17. Реализация виртуального наследования: проблема конструирования подобъектов (3) class A { int m_a; A() {m_a = 0;} }; class B : virtual A {B(){}}; class C : virtual A {C(){}}; class D : B, C {D(){}}; void test() { B b; C c; D d; } A::A(A* this) {this->m_a = 0;} B::B(B* this, bool bMostDerived) { if(bMostDerived) A::A(this+B::delta_A()); } // То же для C… D::D(D* this, bool bMostDerived) { if(bMostDerived) A::A(this+D::delta_A()); B::B(this+D::delta_B(), false); C::C(this+D::delta_C(), false); } void test() { B b; B::B(&b, true); // То же для C… D d; D::D(&d, true); }
  • 18.
  • 19.
  • 20.
  • 21. Специальный трюк: закрытое виртуальное наследование Задача: мы хотим, чтобы базовый класс мог бы «настраиваться» на каждый свой производный класс с помощью некоторых данных, специфичных для этого производного класса. // Файл Gadget.h class GadgetData {…}; class GadgetBase { protected: GadgetData m_GadgetData; GadgetBase(const GadgetData& x) {m_GadgetData = x;} }; class Gadget : private virtual GadgetBase {…}; // Файл FunnyGadget.h #include “Gadget.h” class FunnyGadget : public Gadget { static GadgetData s_FunnyData; public: SpecialGadget() : GadgetBase(s_FunnyData) {} };

Notas do Editor

  1. Public vs. protected interface - two types of clients {part. Meyers1.41}. Containment as "has-a" or "is-implemented-via" relationship {Meyers1.40} Private inheritance - reasons of use instead of containment {Meyers1.42}