" Sanal temel sınıf " ın ne olduğunu ve ne anlama geldiğini bilmek istiyorum .
Bir örnek göstereyim:
class Foo
{
public:
void DoSomething() { /* ... */ }
};
class Bar : public virtual Foo
{
public:
void DoSpecific() { /* ... */ }
};
" Sanal temel sınıf " ın ne olduğunu ve ne anlama geldiğini bilmek istiyorum .
Bir örnek göstereyim:
class Foo
{
public:
void DoSomething() { /* ... */ }
};
class Bar : public virtual Foo
{
public:
void DoSpecific() { /* ... */ }
};
Yanıtlar:
Sanal kalıtımda kullanılan sanal temel sınıflar, belirli bir sınıfın çoklu kalıtım hiyerarşisinde görünen birden çok "örneğini" önlemenin bir yoludur.
Aşağıdaki senaryoyu düşünün:
class A { public: void Foo() {} };
class B : public A {};
class C : public A {};
class D : public B, public C {};
Yukarıdaki sınıf hiyerarşisi şuna benzer "korkunç elmas" ile sonuçlanır:
A
/ \
B C
\ /
D
D örneği A'yı içeren B'yi ve A'yı da içeren C'yi içerecektir. Böylece A'nın iki "örneğini" (daha iyi ifade etmek için) var.
Bu senaryoya sahip olduğunuzda, belirsizlik olasılığınız olur. Bunu yaptığınızda ne olur:
D d;
d.Foo(); // is this B's Foo() or C's Foo() ??
Bu sorunu çözmek için sanal kalıtım var. Sınıflarınızı devralırken sanal belirttiğinizde, derleyiciye yalnızca tek bir örnek istediğinizi söylersiniz.
class A { public: void Foo() {} };
class B : public virtual A {};
class C : public virtual A {};
class D : public B, public C {};
Bu, hiyerarşide A'nın yalnızca bir "örneği" olduğu anlamına gelir. bundan dolayı
D d;
d.Foo(); // no longer ambiguous
Bu küçük bir özet. Daha fazla bilgi için bunu ve bunu okuyun . Burada da iyi bir örnek var .
virtual
, nesne düzeninin elmas gibi görünmesidir; ve eğer kullanmazsak virtual
nesne düzeni iki A
s içeren bir ağaç yapısına benziyor
Bir yan not olarak, Dreaded Diamond ile ilgili sorun, temel sınıfın birçok kez mevcut olmasıdır. Yani düzenli miras ile, sahip olduğunuza inanıyorsunuz:
A
/ \
B C
\ /
D
Ancak bellek düzeninde:
A A
| |
B C
\ /
D
Bu, çağrı yaparken neden D::foo()
bir belirsizlik sorununuz olduğunu açıklar . Ancak asıl sorun, üye değişkenini kullanmak istediğinizde ortaya çıkar A
. Örneğin, diyelim ki:
class A
{
public :
foo() ;
int m_iValue ;
} ;
Erişmeye çalışacağım zaman m_iValue
gelen D
hiyerarşisinde, bu iki göreceksiniz, çünkü derleyici, protesto edecek m_iValue
, bir değil. Ve bir tanesini değiştirirseniz, diyelim ki, B::m_iValue
(yani A::m_iValue
ebeveyni B
), C::m_iValue
değiştirilmeyecektir ( A::m_iValue
ebeveyni C
).
Sanal kalıtımın işe yaradığı yer, burada olduğu gibi, sadece tek bir foo()
yöntemle değil , aynı zamanda bir ve sadece biriyle gerçek bir elmas düzenine geri döneceksiniz m_iValue
.
Hayal etmek:
A
bazı temel özelliklere sahiptir.B
buna bir çeşit harika veri dizisi ekler (örneğin)C
bir gözlemci deseni gibi harika bir özellik ekler (örneğin, açık m_iValue
).D
devralır B
ve C
ve böylece gelen A
.Normal miras ile değiştirerek m_iValue
gelen D
belirsiz ve bu çözülmelidir. Olsa bile, içeride iki tane m_iValues
var D
, bu yüzden bunu hatırlamanız ve aynı anda ikisini güncellemeniz daha iyi olur.
Sanal miras sayesinde, modifiye m_iValue
dan D
sahip olduğun ... Hadi diyelim tamam ... Ama D
. C
Arayüzü sayesinde bir gözlemci iliştirdiniz. Ve B
arayüzü sayesinde, doğrudan değiştirmenin yan etkisi olan serin diziyi güncellersiniz m_iValue
...
Değişikliği m_iValue
doğrudan yapıldığından (sanal bir erişimci yöntemi kullanmadan), "dinleyen" gözlemci C
çağrılmaz, çünkü dinlemeyi uygulayan kod içeride C
ve B
bunu bilmez ...
Hiyerarşinizde bir elmas varsa, bu hiyerarşide yanlış bir şey yapma olasılığınızın% 95 olduğu anlamına gelir.
Çoklu kalıtımın sanal tabanlarla açıklanması, C ++ nesne modeli hakkında bilgi gerektirir. Ve konuyu açık bir şekilde açıklamak en iyi yorum kutusunda değil, bir makalede yapılır.
Bu konudaki tüm şüphelerimi çözdüğünü bulduğum en iyi, okunabilir açıklama bu makaleydi: http://www.phpcompiler.org/articles/virtualinheritance.html
Bunu okuduktan sonra (derleyici yazar değilseniz) konuyla ilgili başka bir şey okumanız gerekmeyecek ...
Sanal temel sınıf, somutlaştırılamayan bir sınıftır: buradan doğrudan nesne oluşturamazsınız.
Bence çok farklı iki şeyi karıştırıyorsun. Sanal kalıtım soyut bir sınıfla aynı şey değildir. Sanal kalıtım işlev çağrılarının davranışını değiştirir; bazen aksi takdirde belirsiz olan fonksiyon çağrılarını çözer, bazen sanal olmayan bir mirasta beklediğinden farklı bir sınıfa fonksiyon çağrısı işlemeyi bozar.
OJ'nin nazik açıklamalarına eklemek istiyorum.
Sanal kalıtım bedelsiz gelmez. Sanal her şeyde olduğu gibi, bir performans vuruşu elde edersiniz. Bu performans vuruşunun etrafında muhtemelen daha az zarif olan bir yol var.
Neredeyse türeterek pırlantayı kırmak yerine, pırlantaya başka bir katman ekleyebilir, şöyle bir şey elde edebilirsiniz:
B
/ \
D11 D12
| |
D21 D22
\ /
DD
Sınıfların hiçbiri sanal olarak miras almıyor, hepsi de alenen miras alıyor. D21 ve D22 sınıfları daha sonra DD için belirsiz olan f () sanal fonksiyonunu, belki de özel fonksiyonunu ilan ederek gizleyecektir. Her biri sırasıyla bir sarmalayıcı işlevi tanımlarlar, sırasıyla f1 () ve f2 (), her biri sınıf-yerel (özel) f () olarak adlandırılır, böylece çatışmalar çözülür. DD sınıfı, D11 :: f () istiyorsa f1 () ve D12 :: f () istiyorsa f2 () öğesini çağırır. Sargıları satır içinde tanımlarsanız, muhtemelen sıfır ek yük alırsınız.
Tabii ki, D11 ve D12'yi değiştirebilirseniz, bu sınıfların içinde aynı hileyi yapabilirsiniz, ancak çoğu zaman böyle değildir.
Çoklu ve sanal kalıtım (lar) hakkında daha önce söylenenlere ek olarak, Dr Dobb'un Dergisi: Çoklu Kalıtım Yararlı Olduğu Yararlı bir makale var
Biraz kafa karıştırıcısın. Bazı kavramları karıştırıp karıştırmadığınızı bilmiyorum.
OP'nizde sanal bir temel sınıfınız yok. Sadece bir temel sınıfınız var.
Sanal miras yaptın. Bu genellikle çoklu kalıtımda kullanılır, böylece çoklu türetilmiş sınıflar, temel sınıfın üyelerini çoğaltmadan kullanır.
Saf sanal işlevi olan bir temel sınıf somutlaştırılmaz. bu Paul'ün sözdizimini gerektirir. Genellikle türetilmiş sınıfların bu işlevleri tanımlaması gerekir.
Bu konuda daha fazla açıklamak istemiyorum çünkü sorduğunuz şeyi tam olarak anlayamıyorum.
Bu, sanal bir işleve yapılan çağrının "sağ" sınıfa yönlendirileceği anlamına gelir.
C ++ SSS Lite FTW.
Kısacası, genellikle bir "elmas" hiyerarşisinin oluştuğu çoklu kalıtım senaryolarında kullanılır. Sanal devralma, daha sonra, o sınıftaki işlevi çağırdığınızda ve işlevin o alt sınıfın üzerindeki D1 veya D2 sınıfına çözümlenmesi gerektiğinde, alt sınıfta oluşturulan belirsizliği bozar. Bkz SSS öğeyi bir diyagram ve detaylar için.
Aynı zamanda güçlü bir özellik olan kardeş delegasyonunda da kullanılır (ancak kalp zayıflığı için değil). Bu SSS'ye bakın .
Ayrıca, Etkili C ++ 3. baskıdaki Madde 40'a (2. baskıdaki 43) bakın.
Elmas miras çalıştırılabilir kullanım örneği
Bu örnek, tipik bir senaryoda sanal bir taban sınıfının nasıl kullanılacağını gösterir: elmas mirasını çözmek için.
#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);
ana işlev bana derleme hatası veriyor: aDefault is not a member of A
gcc 5.4.0 kullanarak. Ne yapmalı?
Sanal sınıflar, sanal kalıtımla aynı şey değildir . Anlayamadığınız sanal sınıflar, sanal kalıtım tamamen başka bir şeydir.
Wikipedia bunu benden daha iyi anlatıyor. http://en.wikipedia.org/wiki/Virtual_inheritance
Tipik 3 seviyeli elmas olmayan sanal olmayan kalıtım mirasıyla, en çok türetilmiş yeni bir nesneyi başlattığınızda, yeni çağrılır ve nesne için gereken boyut derleyici tarafından sınıf türünden çözülür ve yeniye geçirilir.
yeni bir imzası var:
_GLIBCXX_WEAK_DEFINITION void *
operator new (std::size_t sz) _GLIBCXX_THROW (std::bad_alloc)
Ve malloc
boş işaretçiyi döndürerek bir çağrı yapar
Bu daha sonra hemen orta yapıcıyı çağıracak ve daha sonra orta yapıcı hemen taban yapıcısını çağıracak olan en türetilmiş nesnenin yapıcısına geçirilir. Taban daha sonra nesnenin başlangıcında sanal tablosuna bir işaretçi ve sonrasında da niteliklerini depolar. Bu, daha sonra sanal tablo işaretçisini aynı konumda depolayacak olan orta kurucuya ve daha sonra temel kurucu tarafından saklanacak niteliklerden sonra niteliklerine geri döner. İşaretçiyi sanal tablosuna aynı konumda ve daha sonra da orta kurucu tarafından saklanacak niteliklerden sonraki niteliklerini depolayan en türetilmiş kurucuya döner.
Sanal tablo işaretçisinin üzerine yazıldığından, sanal tablo işaretçisi her zaman en türetilmiş sınıftan biri olur. Sanallık en türetilmiş sınıfa doğru ilerler, bu nedenle bir işlev orta sınıfta sanal ise, en çok türetilmiş sınıfta sanal olur, ancak temel sınıfta olmaz. En türetilmiş sınıfın bir örneğini temel sınıfa bir işaretçiye polimorfik olarak uygularsanız, derleyici bunu sanal tabloya yapılan dolaylı çağrıya çözümlemez ve bunun yerine işlevi doğrudan çağırır A::function()
. Bir işlev, onu yayınladığınız tür için sanal ise, o zaman sanal tabloya her zaman en türetilmiş sınıfın işlevi olacak bir çağrıyı çözer. Bu tür için sanal değilse Type::function()
, nesne işaretçisini çağırır ve ona iletir, Tür'e yayınlar.
Aslında sanal tablosuna işaretçi dediğimde, sanal tabloya her zaman 16'lık bir ofset.
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+16
virtual
daha az türetilmiş bir sınıfta sanal olması nedeniyle daha türetilmiş sınıflarda yeniden gerekli değildir. Ancak, fonksiyonun gerçekten de sanal bir fonksiyon olduğunu göstermek için kullanılabilir, sınıflarının tip tanımlarını miras almak zorunda kalmadan.
override
bu işlevin bir şeyi geçersiz kıldığını söyleyen başka bir derleyici koruyucusudur ve eğer değilse bir derleyici hatası atar.
= 0
bunun soyut bir işlev olduğu anlamına gelir
final
sanal işlevin daha türetilmiş bir sınıfta yeniden uygulanmasını engeller ve en türetilmiş sınıfın sanal tablosunun bu sınıfın son işlevini içerdiğinden emin olur.
= default
dokümantasyonda derleyicinin varsayılan uygulamayı kullanacağını açıkça belirtir
= delete
buna bir çağrı yapılmaya çalışılırsa derleyici hatası ver
Düşünmek
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();
}
Bas sınıfını neredeyse miras almadan, şöyle görünen bir nesne elde edersiniz:
Bunun yerine:
Yani 2 temel nesne olacak.
Yeni çağrıldıktan sonra yukarıda sanal elmas miras durumda, bu en türetilmiş yapıcı çağrıları ve bu yapıcı içinde, bunun yerine sadece çağıran çağıran, onun sanal masa tabloya uzaklıklar geçen bütün 3 türetilen Kurucular çağırır DerivedClass1::DerivedClass1()
ve DerivedClass2::DerivedClass2()
sonra bu hem arama veBase::Base()
Aşağıdakilerin tümü -O0 hata ayıklama modunda derlenir, bu nedenle yedekli montaj yapılır
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 d
DerivedDerivedClass::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()
Nesne ofsetine (32) bir işaretçi ile çağrı yapar. Base, aldığı adrese ve sonrasındaki üyelerine sanal tablosuna bir işaretçi depolar.
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
ret
DerivedDerivedClass::DerivedDerivedClass()
daha sonra DerivedClass1::DerivedClass1()
nesne ofseti 0'a bir işaretçi ile çağrı yapar ve ayrıcaVTT 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
ret
VTT 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()
Daha sonra nesne + 16 adresini ve için VTT adresini geçer DerivedDerivedClass+24
için DerivedClass2::DerivedClass2()
montaj aynıdır olan DerivedClass1::DerivedClass1()
hattı için hariç mov DWORD PTR [rax+8], 3
belli bir yerine 4 3 sahiptir d = 4
.
Bundan sonra, nesnedeki 3 sanal tablo işaretçisinin tümünü DerivedDerivedClass
, bu sınıfın gösterimine göre ofsetlere işaretçilerle değiştirir .
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 rdx
d->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 rdx
d->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 rax
d->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