ฉันต้องการรู้ว่า " คลาสฐานเสมือน " คืออะไรและมันหมายถึงอะไร
ให้ฉันแสดงตัวอย่าง:
class Foo
{
public:
    void DoSomething() { /* ... */ }
};
class Bar : public virtual Foo
{
public:
    void DoSpecific() { /* ... */ }
};ฉันต้องการรู้ว่า " คลาสฐานเสมือน " คืออะไรและมันหมายถึงอะไร
ให้ฉันแสดงตัวอย่าง:
class Foo
{
public:
    void DoSomething() { /* ... */ }
};
class Bar : public virtual Foo
{
public:
    void DoSpecific() { /* ... */ }
};คำตอบ:
คลาสพื้นฐานเสมือนที่ใช้ในการสืบทอดเสมือนเป็นวิธีการป้องกัน "อินสแตนซ์" ของคลาสที่กำหนดให้ปรากฏในลำดับชั้นการสืบทอดเมื่อใช้หลายการสืบทอด
พิจารณาสถานการณ์สมมติต่อไปนี้:
class A { public: void Foo() {} };
class B : public A {};
class C : public A {};
class D : public B, public C {};ลำดับชั้นของคลาสด้านบนส่งผลให้ "เพชรที่หวั่น" ซึ่งมีลักษณะดังนี้:
  A
 / \
B   C
 \ /
  Dอินสแตนซ์ของ D จะถูกสร้างขึ้นจาก B ซึ่งรวมถึง A และ C ซึ่งรวมถึง A. ดังนั้นคุณจึงมี "อินสแตนซ์" สองอัน (สำหรับความต้องการในการแสดงออกที่ดีกว่า) ของ A
เมื่อคุณมีสถานการณ์นี้คุณมีความเป็นไปได้ของความคลุมเครือ จะเกิดอะไรขึ้นเมื่อคุณทำสิ่งนี้:
D d;
d.Foo(); // is this B's Foo() or C's Foo() ??การสืบทอดเสมือนอยู่ที่นั่นเพื่อแก้ไขปัญหานี้ เมื่อคุณระบุเวอร์ชวลเมื่อรับคลาสคุณจะบอกคอมไพเลอร์ว่าคุณต้องการอินสแตนซ์เดียวเท่านั้น
class A { public: void Foo() {} };
class B : public virtual A {};
class C : public virtual A {};
class D : public B, public C {};ซึ่งหมายความว่ามี "อินสแตนซ์" เดียวของ A รวมอยู่ในลำดับชั้น ด้วยเหตุนี้
D d;
d.Foo(); // no longer ambiguousนี่คือสรุปย่อ สำหรับข้อมูลเพิ่มเติมได้อ่านจากนี้และนี้ เป็นตัวอย่างที่ดียังมีอยู่ที่นี่
virtualแล้วเค้าโครงของวัตถุจะดูเหมือนเพชร และถ้าเราไม่ได้ใช้virtualรูปแบบวัตถุจะดูเหมือนโครงสร้างต้นไม้ที่มีสองAs
                    จากบันทึกด้านข้างปัญหาของ Dreaded Diamond คือว่าคลาสพื้นฐานมีอยู่หลายครั้ง ดังนั้นด้วยมรดกอย่างสม่ำเสมอคุณเชื่อว่าคุณมี:
  A
 / \
B   C
 \ /
  Dแต่ในโครงร่างหน่วยความจำคุณมี:
A   A
|   |
B   C
 \ /
  Dสิ่งนี้อธิบายว่าทำไมเมื่อมีการโทรD::foo()คุณมีปัญหาความกำกวม แต่จริงAปัญหามาเมื่อคุณต้องการที่จะใช้ตัวแปรสมาชิกของ ตัวอย่างเช่นสมมติว่าเรามี:
class A
{
    public :
       foo() ;
       int m_iValue ;
} ;เมื่อคุณจะพยายามที่จะเข้าถึงm_iValueจากDคอมไพเลอร์จะประท้วงเพราะในลำดับชั้นก็จะเห็นสองm_iValueไม่หนึ่ง และถ้าคุณดัดแปลงหนึ่งพูดB::m_iValue(นั่นคือต้นA::m_iValueกำเนิดของB) C::m_iValueจะไม่ได้รับการแก้ไข (นั่นคือต้นA::m_iValueกำเนิดของC )
นี่คือสิ่งที่มรดกเสมือนจริงใช้งานได้สะดวกเช่นเดียวกับที่คุณจะได้รับกลับไปที่รูปแบบเพชรจริงโดยไม่เพียง แต่foo()วิธีเดียวเท่านั้น แต่ยังมีวิธีหนึ่งเท่านั้นm_iValueแต่ยังเป็นหนึ่งและมีเพียงหนึ่ง
Imagine:
A มีคุณสมบัติพื้นฐานบางอย่างB เพิ่มไปยังข้อมูลบางประเภท (ตัวอย่าง)C เพิ่มคุณสมบัติเจ๋ง ๆ บางอย่างเช่นรูปแบบผู้สังเกตการณ์ (ตัวอย่างเช่นเปิด m_iValue )DสืบทอดจากBและและทำให้จากCAด้วยการสืบทอดปกติการแก้ไขm_iValueจากDจะคลุมเครือและจะต้องแก้ไข แม้ว่ามันจะมีอยู่สองm_iValuesด้านDดังนั้นคุณควรจำไว้และปรับปรุงทั้งสองในเวลาเดียวกัน
ด้วยมรดกเสมือนการปรับเปลี่ยนm_iValueจากการDเป็น ok ... แต่ ... Dพูดเถอะว่าคุณมี Cคุณได้แนบผู้สังเกตการณ์ผ่านทางส่วนต่อประสาน และผ่านBอินเทอร์เฟซคุณจะอัปเดตอาร์เรย์สุดเจ๋งซึ่งมีผลข้างเคียงของการเปลี่ยนแปลงโดยตรงm_iValue ...
เมื่อมีการเปลี่ยนแปลงm_iValueโดยตรง (โดยไม่ต้องใช้วิธีการเข้าถึงเสมือน) ผู้สังเกตการณ์ "การฟัง" Cจะไม่ถูกเรียกเนื่องจากรหัสที่ใช้ในการฟังอยู่CและBไม่ทราบ ...
หากคุณมีเพชรอยู่ในลำดับชั้นของคุณหมายความว่าคุณมีโอกาส 95% ที่จะทำอะไรผิดพลาดกับลำดับชั้นดังกล่าว
การอธิบายการสืบทอดหลายแบบพร้อมฐานเสมือนต้องมีความรู้เกี่ยวกับโมเดลวัตถุ C ++ และการอธิบายหัวข้ออย่างชัดเจนทำได้ดีที่สุดในบทความและไม่ได้อยู่ในช่องแสดงความคิดเห็น
คำอธิบายที่ดีที่สุดที่อ่านได้ฉันพบว่าการแก้ไขข้อสงสัยทั้งหมดของฉันในหัวข้อนี้คือบทความนี้: http://www.phpcompiler.org/articles/virtualinheritance.html
คุณไม่จำเป็นต้องอ่านอะไรอีกเลยในหัวข้อ (เว้นแต่คุณจะเป็นนักเขียนคอมไพเลอร์) หลังจากอ่านแล้ว ...
คลาสฐานเสมือนเป็นคลาสที่ไม่สามารถสร้างอินสแตนซ์ได้: คุณไม่สามารถสร้างวัตถุโดยตรงจากคลาสนั้น
ฉันคิดว่าคุณกำลังสับสนสองสิ่งที่แตกต่างกันมาก การสืบทอดเสมือนจริงไม่ใช่สิ่งเดียวกับคลาสนามธรรม การสืบทอดเสมือนจะปรับเปลี่ยนพฤติกรรมของการเรียกใช้ฟังก์ชัน บางครั้งมันแก้ไขการเรียกฟังก์ชันที่มิฉะนั้นจะคลุมเครือบางครั้งมัน defers จัดการฟังก์ชันการโทรไปยังคลาสอื่นนอกเหนือจากที่คาดว่าจะได้รับในการสืบทอดที่ไม่ใช่เสมือน
ฉันต้องการเพิ่มความกระจ่างของ OJ
การสืบทอดเสมือนไม่ได้มาโดยไม่มีราคา เช่นเดียวกับทุกสิ่งเสมือนจริงคุณจะได้รับผลงานยอดเยี่ยม มีวิธีแก้ไขปัญหาเกี่ยวกับการแสดงที่อาจมีความสง่างามน้อยลง
คุณสามารถเพิ่มอีกชั้นหนึ่งลงในเพชรเพื่อให้ได้สิ่งนี้:
   B
  / \
D11 D12
 |   |
D21 D22
 \   /
  DDไม่มีคลาสใดที่สืบทอดมาอย่างแท้จริงทุกคนสืบทอดต่อสาธารณะ คลาส D21 และ D22 จะซ่อนฟังก์ชันเสมือน f () ซึ่งไม่ชัดเจนสำหรับ DD ซึ่งอาจเป็นการประกาศฟังก์ชั่นส่วนตัว พวกเขาแต่ละคนจะกำหนดฟังก์ชั่น wrapper, f1 () และ f2 () ตามลำดับแต่ละคนเรียก class-local (ส่วนตัว) f () เพื่อแก้ไขความขัดแย้ง คลาส DD เรียกใช้ f1 () ถ้าต้องการ D11 :: f () และ f2 () ถ้าต้องการ D12 :: f () หากคุณกำหนดคำว่า "อินไลน์" ไว้คุณอาจได้รับค่าโสหุ้ยเป็นศูนย์
แน่นอนถ้าคุณสามารถเปลี่ยน D11 และ D12 ได้คุณสามารถทำแบบเดียวกันภายในคลาสเหล่านี้ได้ แต่บ่อยครั้งที่มันไม่ได้เป็นเช่นนั้น
นอกจากสิ่งที่ได้กล่าวไปแล้วเกี่ยวกับการสืบทอดหลายครั้งและเสมือนจริงแล้วยังมีบทความที่น่าสนใจมากในวารสารของด๊อบบ์: การรับมรดกหลายรายการถือว่ามีประโยชน์
คุณกำลังสับสนเล็กน้อย ฉันไม่รู้ว่าคุณกำลังทำมโนทัศน์กันบ้างไหม
คุณไม่มีคลาสฐานเสมือนใน OP ของคุณ คุณมีคลาสพื้นฐาน
คุณได้รับมรดกเสมือนจริง โดยปกติจะใช้ในการสืบทอดหลายคลาสดังนั้นคลาสที่ได้รับจำนวนมากจะใช้สมาชิกของคลาสฐานโดยไม่ต้องสร้างซ้ำ
คลาสพื้นฐานที่มีฟังก์ชันเสมือนจริงไม่ได้ถูกสร้างขึ้นมา สิ่งนี้ต้องใช้ไวยากรณ์ที่พอลได้รับ โดยทั่วไปจะใช้เพื่อให้คลาสที่ได้รับต้องกำหนดฟังก์ชันเหล่านั้น
ฉันไม่ต้องการอธิบายเรื่องนี้อีกเพราะฉันไม่ได้รับสิ่งที่คุณขอทั้งหมด
มันหมายถึงการเรียกไปยังฟังก์ชั่นเสมือนจริงจะถูกส่งต่อไปยังระดับ "ขวา"
C ++ FAQ Lite FTW
กล่าวโดยย่อมักใช้ในสถานการณ์จำลองหลายมรดกที่มีลำดับชั้น "ไดมอนด์" การสืบทอดเสมือนจะทำให้เกิดความกำกวมที่สร้างในคลาสล่างเมื่อคุณเรียกใช้ฟังก์ชันในคลาสนั้นและฟังก์ชันจำเป็นต้องแก้ไขเป็นคลาส D1 หรือ D2 เหนือคลาสระดับล่างนั้น ดูรายการคำถามที่พบบ่อยสำหรับแผนภาพและรายละเอียด
มันยังใช้ในการมอบสิทธิ์น้องสาวซึ่งเป็นคุณสมบัติที่ทรงพลัง (แม้ว่าจะไม่ใช่เพราะใจอ่อน) ดูนี่สิคำถามที่พบบ่อย
ดูรายการ 40 ใน C ++ รุ่นที่ 3 ที่มีประสิทธิภาพ (43 ในรุ่นที่ 2)
ตัวอย่างการใช้งานที่สืบทอดได้ของ Diamond
ตัวอย่างนี้แสดงวิธีใช้คลาสฐานเสมือนในสถานการณ์ทั่วไป: เพื่อแก้ปัญหาการสืบทอดเพชร
#include <cassert>
class A {
    public:
        A(){}
        A(int i) : i(i) {}
        int i;
        virtual int f() = 0;
        virtual int g() = 0;
        virtual int h() = 0;
};
class B : public virtual A {
    public:
        B(int j) : j(j) {}
        int j;
        virtual int f() { return this->i + this->j; }
};
class C : public virtual A {
    public:
        C(int k) : k(k) {}
        int k;
        virtual int g() { return this->i + this->k; }
};
class D : public B, public C {
    public:
        D(int i, int j, int k) : A(i), B(j), C(k) {}
        virtual int h() { return this->i + this->j + this->k; }
};
int main() {
    D d = D(1, 2, 4);
    assert(d.f() == 3);
    assert(d.g() == 5);
    assert(d.h() == 7);
}assert(A::aDefault == 0);จากฟังก์ชั่นหลักทำให้ฉันมีข้อผิดพลาดในการรวบรวม: aDefault is not a member of Ausing gcc 5.4.0 มันควรจะทำอะไร?
                    คลาสเสมือนไม่ได้เหมือนกับมรดกเสมือน คลาสเสมือนที่คุณไม่สามารถสร้างอินสแตนซ์ได้การสืบทอดเสมือนเป็นอย่างอื่นทั้งหมด
Wikipedia อธิบายได้ดีกว่าที่ฉันทำได้ http://en.wikipedia.org/wiki/Virtual_inheritance

ด้วยระดับทั่วไป 3 ระดับไม่ใช่เพชรไม่ใช่มรดกเสมือนเมื่อคุณยกตัวอย่างวัตถุที่ได้มามากที่สุดใหม่จะถูกเรียกใหม่และขนาดที่ต้องการสำหรับวัตถุนั้นได้รับการแก้ไขจากประเภทคลาสโดยคอมไพเลอร์และส่งไปยังใหม่
ใหม่มีลายเซ็น:
_GLIBCXX_WEAK_DEFINITION void *
operator new (std::size_t sz) _GLIBCXX_THROW (std::bad_alloc)และทำการโทรออก mallocกลับเป็นตัวชี้โมฆะ
สิ่งนี้จะถูกส่งไปยังตัวสร้างของวัตถุที่ได้รับมามากที่สุดซึ่งจะเรียกผู้สร้างตรงกลางทันทีจากนั้นตัวสร้างกลางจะเรียกผู้สร้างฐานทันที จากนั้นฐานจะเก็บตัวชี้ไปยังตารางเสมือนของมันที่จุดเริ่มต้นของวัตถุและจากนั้นแอตทริบิวต์ของมันหลังจากนั้น สิ่งนี้จะส่งกลับไปยังตัวสร้างกลางซึ่งจะจัดเก็บตัวชี้ตารางเสมือนของมันที่ตำแหน่งเดียวกันและจากนั้นแอตทริบิวต์ของมันหลังจากแอตทริบิวต์ที่จะถูกจัดเก็บโดยตัวสร้างฐาน มันส่งกลับไปยังตัวสร้างที่ได้รับมากที่สุดซึ่งเก็บตัวชี้ไปยังตารางเสมือนของมันที่ตำแหน่งเดียวกันและจากนั้นแอตทริบิวต์ของมันหลังจากแอตทริบิวต์ที่จะถูกจัดเก็บโดยตัวสร้างกลาง
เนื่องจากตัวชี้ตารางเสมือนถูกเขียนทับตัวชี้ตารางเสมือนจึงกลายเป็นคลาสที่ได้รับมามากที่สุดเสมอ ความเสมือนจริงแพร่กระจายไปสู่คลาสที่ได้รับมากที่สุดดังนั้นหากฟังก์ชันนั้นเสมือนในคลาสกลางมันจะเป็นเสมือนในคลาสที่ได้มามากที่สุด แต่ไม่ใช่คลาสพื้นฐาน ถ้าคุณใช้พร็อกซีแบบอินสแตนซ์ของคลาสที่ได้รับมากที่สุดไปยังตัวชี้ไปยังคลาสพื้นฐานคอมไพเลอร์จะไม่แก้ไขสิ่งนี้เป็นการเรียกทางอ้อมไปยังตารางเสมือนและจะเรียกใช้ฟังก์ชันโดยตรงA::function()แทน หากฟังก์ชั่นเป็นเสมือนจริงสำหรับประเภทที่คุณใช้งานแล้วมันจะแก้ไขการเรียกเข้าไปในตารางเสมือนซึ่งจะเป็นคลาสที่ได้รับมามากที่สุด ถ้าไม่ใช่ชนิดนั้นมันก็จะเรียกType::function()และผ่านตัวชี้วัตถุไปที่มันโยนไปพิมพ์
ที่จริงเมื่อฉันพูดตัวชี้ไปที่ตารางเสมือนจริงมันมักจะชดเชย 16 ลงในตารางเสมือน
vtable for Base:
        .quad   0
        .quad   typeinfo for Base
        .quad   Base::CommonFunction()
        .quad   Base::VirtualFunction()
pointer is typically to the first function i.e. 
        mov     edx, OFFSET FLAT:vtable for Base+16virtualไม่จำเป็นต้องใช้อีกครั้งในคลาสที่ได้รับเพิ่มเติมหากเป็นเสมือนในคลาสที่ได้รับน้อยลงเนื่องจากมันแพร่กระจาย แต่มันสามารถใช้เพื่อแสดงให้เห็นว่าฟังก์ชั่นนั้นเป็นฟังก์ชั่นเสมือนจริงโดยไม่ต้องตรวจสอบคลาสที่ได้รับการกำหนดประเภทของสืบทอด
override เป็นคอมไพเลอร์ตัวป้องกันอีกตัวที่บอกว่าฟังก์ชั่นนี้มีความสำคัญมากกว่าบางอย่างและถ้ามันไม่ได้เกิดข้อผิดพลาดของคอมไพเลอร์
= 0 หมายความว่านี่เป็นฟังก์ชันนามธรรม
final ป้องกันไม่ให้มีการใช้งานฟังก์ชันเสมือนอีกครั้งในคลาสที่ได้รับมากขึ้นและจะทำให้แน่ใจว่าตารางเสมือนของคลาสที่ได้รับมาส่วนใหญ่จะมีฟังก์ชันสุดท้ายของคลาสนั้น
= default ทำให้ชัดเจนในเอกสารประกอบว่าคอมไพเลอร์จะใช้การใช้งานเริ่มต้น
= delete ให้ข้อผิดพลาดคอมไพเลอร์หากพยายามโทรนี้ 
พิจารณา
class Base
  {
      int a = 1;
      int b = 2;
  public:
      void virtual CommonFunction(){} ;
      void virtual VirtualFunction(){} ;
  };
class DerivedClass1: virtual public Base
  {
      int c = 3;
  public:
    void virtual DerivedCommonFunction(){} ;
     void virtual VirtualFunction(){} ;
  };
  class DerivedClass2 : virtual public Base
 {
     int d = 4;
 public:
     //void virtual DerivedCommonFunction(){} ;    
     void virtual VirtualFunction(){} ;
     void virtual DerivedCommonFunction2(){} ;
 };
class DerivedDerivedClass :  public DerivedClass1, public DerivedClass2
 {
   int e = 5;
 public:
     void virtual DerivedDerivedCommonFunction(){} ;
     void virtual VirtualFunction(){} ;
 };
 int main () {
   DerivedDerivedClass* d = new DerivedDerivedClass;
   d->VirtualFunction();
   d->DerivedCommonFunction();
   d->DerivedCommonFunction2();
   d->DerivedDerivedCommonFunction();
   ((DerivedClass2*)d)->DerivedCommonFunction2();
   ((Base*)d)->VirtualFunction();
 }คุณจะได้รับวัตถุที่มีลักษณะดังนี้:

แทนสิ่งนี้:

นั่นคือจะมีวัตถุฐาน 2
ในสถานการณ์การสืบทอดเพชรเสมือนด้านบนหลังจากใหม่ถูกเรียกมันเรียกนวกรรมิกที่ได้รับมามากที่สุดและในนวกรรมิกนั้นมันเรียกสิ่งก่อสร้างที่ได้รับมาทั้ง 3 ตัวที่ผ่านการหักล้างเข้าไปในตารางตารางเสมือนแทนที่จะเรียกเพียงDerivedClass1::DerivedClass1()และDerivedClass2::DerivedClass2()แล้วที่ทั้งสองได้โทรBase::Base()
ต่อไปนี้คือทั้งหมดที่รวบรวมในโหมดการแก้ปัญหา -O0 ดังนั้นจะมีการชุมนุมซ้ำซ้อน
main:
.LFB8:
        push    rbp
        mov     rbp, rsp
        push    rbx
        sub     rsp, 24
        mov     edi, 48 //pass size to new
        call    operator new(unsigned long) //call new
        mov     rbx, rax  //move the address of the allocation to rbx
        mov     rdi, rbx  //move it to rdi i.e. pass to the call
        call    DerivedDerivedClass::DerivedDerivedClass() [complete object constructor] //construct on this address
        mov     QWORD PTR [rbp-24], rbx  //store the address of the object on the stack as dDerivedDerivedClass::DerivedDerivedClass() [complete object constructor]:
.LFB20:
        push    rbp
        mov     rbp, rsp
        sub     rsp, 16
        mov     QWORD PTR [rbp-8], rdi
.LBB5:
        mov     rax, QWORD PTR [rbp-8] // object address now in rax 
        add     rax, 32 //increment address by 32
        mov     rdi, rax // move object address+32 to rdi i.e. pass to call
        call    Base::Base() [base object constructor]
        mov     rax, QWORD PTR [rbp-8] //move object address to rax
        mov     edx, OFFSET FLAT:VTT for DerivedDerivedClass+8 //move address of VTT+8 to edx
        mov     rsi, rdx //pass VTT+8 address as 2nd parameter 
        mov     rdi, rax //object address as first
        call    DerivedClass1::DerivedClass1() [base object constructor]
        mov     rax, QWORD PTR [rbp-8] //move object address to rax
        add     rax, 16  //increment object address by 16
        mov     edx, OFFSET FLAT:VTT for DerivedDerivedClass+24  //store address of VTT+24 in edx
        mov     rsi, rdx //pass address of VTT+24 as second parameter
        mov     rdi, rax //address of object as first
        call    DerivedClass2::DerivedClass2() [base object constructor]
        mov     edx, OFFSET FLAT:vtable for DerivedDerivedClass+24 //move this to edx
        mov     rax, QWORD PTR [rbp-8] // object address now in rax
        mov     QWORD PTR [rax], rdx. //store address of vtable for DerivedDerivedClass+24 at the start of the object
        mov     rax, QWORD PTR [rbp-8] // object address now in rax
        add     rax, 32  // increment object address by 32
        mov     edx, OFFSET FLAT:vtable for DerivedDerivedClass+120 //move this to edx
        mov     QWORD PTR [rax], rdx  //store vtable for DerivedDerivedClass+120 at object+32 (Base) 
        mov     edx, OFFSET FLAT:vtable for DerivedDerivedClass+72 //store this in edx
        mov     rax, QWORD PTR [rbp-8] //move object address to rax
        mov     QWORD PTR [rax+16], rdx //store vtable for DerivedDerivedClass+72 at object+16 (DerivedClass2)
        mov     rax, QWORD PTR [rbp-8]
        mov     DWORD PTR [rax+28], 5
.LBE5:
        nop
        leave
        retมันเรียกBase::Base()ด้วยตัวชี้ไปยังวัตถุชดเชย 32 ฐานเก็บตัวชี้ไปยังตารางเสมือนที่อยู่ที่ได้รับและสมาชิกหลังจากนั้น
Base::Base() [base object constructor]:
.LFB11:
        push    rbp
        mov     rbp, rsp
        mov     QWORD PTR [rbp-8], rdi //stores address of object on stack (-O0)
.LBB2:
        mov     edx, OFFSET FLAT:vtable for Base+16  //puts vtable for Base+16 in edx
        mov     rax, QWORD PTR [rbp-8] //copies address of object from stack to rax
        mov     QWORD PTR [rax], rdx  //stores it address of object
        mov     rax, QWORD PTR [rbp-8] //copies address of object on stack to rax again
        mov     DWORD PTR [rax+8], 1 //stores a = 1 in the object
        mov     rax, QWORD PTR [rbp-8] //junk from -O0
        mov     DWORD PTR [rax+12], 2  //stores b = 2 in the object
.LBE2:
        nop
        pop     rbp
        retDerivedDerivedClass::DerivedDerivedClass()จากนั้นเรียกใช้DerivedClass1::DerivedClass1()พร้อมกับตัวชี้ไปยังอ็อฟเซ็ต 0 และส่งผ่านที่อยู่ของVTT for DerivedDerivedClass+8
DerivedClass1::DerivedClass1() [base object constructor]:
.LFB14:
        push    rbp
        mov     rbp, rsp
        mov     QWORD PTR [rbp-8], rdi //address of object
        mov     QWORD PTR [rbp-16], rsi  //address of VTT+8
.LBB3:
        mov     rax, QWORD PTR [rbp-16]  //address of VTT+8 now in rax
        mov     rdx, QWORD PTR [rax]     //address of DerivedClass1-in-DerivedDerivedClass+24 now in rdx
        mov     rax, QWORD PTR [rbp-8]   //address of object now in rax
        mov     QWORD PTR [rax], rdx     //store address of DerivedClass1-in-.. in the object
        mov     rax, QWORD PTR [rbp-8]  // address of object now in rax
        mov     rax, QWORD PTR [rax]    //address of DerivedClass1-in.. now implicitly in rax
        sub     rax, 24                 //address of DerivedClass1-in-DerivedDerivedClass+0 now in rax
        mov     rax, QWORD PTR [rax]    //value of 32 now in rax
        mov     rdx, rax                // now in rdx
        mov     rax, QWORD PTR [rbp-8]  //address of object now in rax
        add     rdx, rax                //address of object+32 now in rdx
        mov     rax, QWORD PTR [rbp-16]  //address of VTT+8 now in rax
        mov     rax, QWORD PTR [rax+8]   //address of DerivedClass1-in-DerivedDerivedClass+72 (Base::CommonFunction()) now in rax
        mov     QWORD PTR [rdx], rax     //store at address object+32 (offset to Base)
        mov     rax, QWORD PTR [rbp-8]  //store address of object in rax, return
        mov     DWORD PTR [rax+8], 3    //store its attribute c = 3 in the object
.LBE3:
        nop
        pop     rbp
        retVTT for DerivedDerivedClass:
        .quad   vtable for DerivedDerivedClass+24
        .quad   construction vtable for DerivedClass1-in-DerivedDerivedClass+24
        .quad   construction vtable for DerivedClass1-in-DerivedDerivedClass+72
        .quad   construction vtable for DerivedClass2-in-DerivedDerivedClass+24
        .quad   construction vtable for DerivedClass2-in-DerivedDerivedClass+72
        .quad   vtable for DerivedDerivedClass+120
        .quad   vtable for DerivedDerivedClass+72
construction vtable for DerivedClass1-in-DerivedDerivedClass:
        .quad   32
        .quad   0
        .quad   typeinfo for DerivedClass1
        .quad   DerivedClass1::DerivedCommonFunction()
        .quad   DerivedClass1::VirtualFunction()
        .quad   -32
        .quad   0
        .quad   -32
        .quad   typeinfo for DerivedClass1
        .quad   Base::CommonFunction()
        .quad   virtual thunk to DerivedClass1::VirtualFunction()
construction vtable for DerivedClass2-in-DerivedDerivedClass:
        .quad   16
        .quad   0
        .quad   typeinfo for DerivedClass2
        .quad   DerivedClass2::VirtualFunction()
        .quad   DerivedClass2::DerivedCommonFunction2()
        .quad   -16
        .quad   0
        .quad   -16
        .quad   typeinfo for DerivedClass2
        .quad   Base::CommonFunction()
        .quad   virtual thunk to DerivedClass2::VirtualFunction()
vtable for DerivedDerivedClass:
        .quad   32
        .quad   0
        .quad   typeinfo for DerivedDerivedClass
        .quad   DerivedClass1::DerivedCommonFunction()
        .quad   DerivedDerivedClass::VirtualFunction()
        .quad   DerivedDerivedClass::DerivedDerivedCommonFunction()
        .quad   16
        .quad   -16
        .quad   typeinfo for DerivedDerivedClass
        .quad   non-virtual thunk to DerivedDerivedClass::VirtualFunction()
        .quad   DerivedClass2::DerivedCommonFunction2()
        .quad   -32
        .quad   0
        .quad   -32
        .quad   typeinfo for DerivedDerivedClass
        .quad   Base::CommonFunction()
        .quad   virtual thunk to DerivedDerivedClass::VirtualFunction()
virtual thunk to DerivedClass1::VirtualFunction():
        mov     r10, QWORD PTR [rdi]
        add     rdi, QWORD PTR [r10-32]
        jmp     .LTHUNK0
virtual thunk to DerivedClass2::VirtualFunction():
        mov     r10, QWORD PTR [rdi]
        add     rdi, QWORD PTR [r10-32]
        jmp     .LTHUNK1
virtual thunk to DerivedDerivedClass::VirtualFunction():
        mov     r10, QWORD PTR [rdi]
        add     rdi, QWORD PTR [r10-32]
        jmp     .LTHUNK2
non-virtual thunk to DerivedDerivedClass::VirtualFunction():
        sub     rdi, 16
        jmp     .LTHUNK3
        .set    .LTHUNK0,DerivedClass1::VirtualFunction()
        .set    .LTHUNK1,DerivedClass2::VirtualFunction()
        .set    .LTHUNK2,DerivedDerivedClass::VirtualFunction()
        .set    .LTHUNK3,DerivedDerivedClass::VirtualFunction()
DerivedDerivedClass::DerivedDerivedClass()แล้วผ่านที่อยู่ของวัตถุ + 16 และที่อยู่ของ VTT สำหรับที่DerivedDerivedClass+24จะDerivedClass2::DerivedClass2()มีการชุมนุมเป็นเหมือนDerivedClass1::DerivedClass1()ยกเว้นบรรทัดmov     DWORD PTR [rax+8], 3ซึ่งเห็นได้ชัดว่ามี 4 แทน d = 43
หลังจากนี้มันจะแทนที่ทั้ง 3 พอยน์เตอร์พอยน์เตอร์ในวัตถุที่มีพอยน์เตอร์เพื่อออฟเซ็ตในDerivedDerivedClassvtable ของมันเพื่อเป็นตัวแทนของคลาสนั้น
d->VirtualFunction();:
        mov     rax, QWORD PTR [rbp-24] //store pointer to virtual table in rax 
        mov     rax, QWORD PTR [rax] //dereference and store in rax
        add     rax, 8 // call the 2nd function in the table
        mov     rdx, QWORD PTR [rax] //dereference 
        mov     rax, QWORD PTR [rbp-24]
        mov     rdi, rax
        call    rdxd->DerivedCommonFunction();:
        mov     rax, QWORD PTR [rbp-24]
        mov     rdx, QWORD PTR [rbp-24]
        mov     rdx, QWORD PTR [rdx]
        mov     rdx, QWORD PTR [rdx]
        mov     rdi, rax
        call    rdxd->DerivedCommonFunction2();:
        mov     rax, QWORD PTR [rbp-24]
        lea     rdx, [rax+16]
        mov     rax, QWORD PTR [rbp-24]
        mov     rax, QWORD PTR [rax+16]
        add     rax, 8
        mov     rax, QWORD PTR [rax]
        mov     rdi, rdx
        call    raxd->DerivedDerivedCommonFunction();:
        mov     rax, QWORD PTR [rbp-24]
        mov     rax, QWORD PTR [rax]
        add     rax, 16
        mov     rdx, QWORD PTR [rax]
        mov     rax, QWORD PTR [rbp-24]
        mov     rdi, rax
        call    rdx((DerivedClass2*)d)->DerivedCommonFunction2();:
        cmp     QWORD PTR [rbp-24], 0
        je      .L14
        mov     rax, QWORD PTR [rbp-24]
        add     rax, 16
        jmp     .L15
.L14:
        mov     eax, 0
.L15:
        cmp     QWORD PTR [rbp-24], 0
        cmp     QWORD PTR [rbp-24], 0
        je      .L18
        mov     rdx, QWORD PTR [rbp-24]
        add     rdx, 16
        jmp     .L19
.L18:
        mov     edx, 0
.L19:
        mov     rdx, QWORD PTR [rdx]
        add     rdx, 8
        mov     rdx, QWORD PTR [rdx]
        mov     rdi, rax
        call    rdx((Base*)d)->VirtualFunction();:
        cmp     QWORD PTR [rbp-24], 0
        je      .L20
        mov     rax, QWORD PTR [rbp-24]
        mov     rax, QWORD PTR [rax]
        sub     rax, 24
        mov     rax, QWORD PTR [rax]
        mov     rdx, rax
        mov     rax, QWORD PTR [rbp-24]
        add     rax, rdx
        jmp     .L21
.L20:
        mov     eax, 0
.L21:
        cmp     QWORD PTR [rbp-24], 0
        cmp     QWORD PTR [rbp-24], 0
        je      .L24
        mov     rdx, QWORD PTR [rbp-24]
        mov     rdx, QWORD PTR [rdx]
        sub     rdx, 24
        mov     rdx, QWORD PTR [rdx]
        mov     rcx, rdx
        mov     rdx, QWORD PTR [rbp-24]
        add     rdx, rcx
        jmp     .L25
.L24:
        mov     edx, 0
.L25:
        mov     rdx, QWORD PTR [rdx]
        add     rdx, 8
        mov     rdx, QWORD PTR [rdx]
        mov     rdi, rax
        call    rdx