类实例化和构造函数
类实例化和构造函数
- 类如何创立,如何调用构造函数
- 源码
- rv汇编
- 行为分析
- 一般成员函数
- 虚函数
- 源码
- 汇编
- 行为分析
- 纯虚函数
- 汇编
- 行为分析
- 多态
- 源码
- 汇编
- 行为分析
- 为什么构造函数不能是虚函数
类如何创立,如何调用构造函数
源码
#include <iostream>
using namespace std;
// 抽象父类
class Base {
int a,b;
public:
Base(){
a=1;
b=2;
}
};
// 子类
class Derived : public Base {
public:
int c;
Derived(){
c=3;
}
};
int main() {
Derived b ;
return 0;
}
rv汇编
__cxx_global_var_init:
addi sp, sp, -16
sw ra, 12(sp)
sw s0, 8(sp)
addi s0, sp, 16
lui a0, %hi(std::__ioinit)
addi a0, a0, %lo(std::__ioinit)
sw a0, -12(s0)
call std::ios_base::Init::Init() [complete object constructor]
lw a1, -12(s0)
lui a0, %hi(_ZNSt8ios_base4InitD1Ev)
addi a0, a0, %lo(_ZNSt8ios_base4InitD1Ev)
lui a2, %hi(__dso_handle)
addi a2, a2, %lo(__dso_handle)
call __cxa_atexit
lw s0, 8(sp)
lw ra, 12(sp)
addi sp, sp, 16
ret
main:
addi sp, sp, -32
sw ra, 28(sp)
sw s0, 24(sp)
addi s0, sp, 32
mv a0, zero
sw a0, -28(s0)
sw a0, -12(s0)
addi a0, s0, -24
call Derived::Derived() [base object constructor]
lw a0, -28(s0)
lw s0, 24(sp)
lw ra, 28(sp)
addi sp, sp, 32
ret
Derived::Derived() [base object constructor]:
addi sp, sp, -16
sw ra, 12(sp)
sw s0, 8(sp)
addi s0, sp, 16
sw a0, -12(s0)
lw a0, -12(s0)
sw a0, -16(s0)
call Base::Base() [base object constructor]
lw a1, -16(s0)
addi a0, zero, 3
sw a0, 8(a1)
lw s0, 8(sp)
lw ra, 12(sp)
addi sp, sp, 16
ret
Base::Base() [base object constructor]:
addi sp, sp, -16
sw ra, 12(sp)
sw s0, 8(sp)
addi s0, sp, 16
sw a0, -12(s0)
lw a1, -12(s0)
addi a0, zero, 1
sw a0, 0(a1)
addi a0, zero, 2
sw a0, 4(a1)
lw s0, 8(sp)
lw ra, 12(sp)
addi sp, sp, 16
ret
_GLOBAL__sub_I_example.cpp:
addi sp, sp, -16
sw ra, 12(sp)
sw s0, 8(sp)
addi s0, sp, 16
call __cxx_global_var_init
lw s0, 8(sp)
lw ra, 12(sp)
addi sp, sp, 16
ret
std::__ioinit:
.zero 1
行为分析
- 在main会去调用Derived的构造函数,并且在调用之前,会给a0寄存器一个地址,这个地址其实是this指针,也就是Derived实例化对象b的地址,main在传入之前已经为b实例开辟了栈空间
- Derived的构造函数的也会传入b的地址给Base的构造函数
- 进入Base构造就不难看出,这里拿着最开始b的地址在做实际的输出化了
lw a1, -12(s0)
addi a0, zero, 1
sw a0, 0(a1)
addi a0, zero, 2
sw a0, 4(a1)
lw s0, 8(sp)
这里是先把地址放在栈上,然后a1拿着地址,之后就往偏移位置放值,这里对应的就是初始化父类的成员变量
- 调用完回到Derived的构造函数,再初始化子类成员变量
lw a1, -16(s0)
addi a0, zero, 3
sw a0, 8(a1)
一般成员函数
#include <iostream>
using namespace std;
// 抽象父类
class Base {
int a,b;
public:
Base(){
a=1;
b=2;
}
};
// 子类
class Derived : public Base {
public:
int c;
Derived(){
c=3;
}
void show(){
cout<<c<<endl;
}
};
int main() {
Derived b ;
b.show();
return 0;
}
这里其实和构造函数一样,调用之气会传入变量的地址,也就是this指针,以便函数使用成员变量
虚函数
源码
#include <iostream>
using namespace std;
class Base {
public:
int a,b;
Base(){
a=1;
b=2;
}
virtual void show1(){
cout<<a<<endl;
}
virtual void show2(){
cout<<a<<endl;
}
};
// 子类
class Derived : public Base {
public:
int c;
Derived(){
c=3;
}
virtual void show2(){
cout<<a<<endl;
}
};
int main() {
Derived b ;
b.show1();
return 0;
}
汇编
__cxx_global_var_init:
addi sp, sp, -16
sw ra, 12(sp)
sw s0, 8(sp)
addi s0, sp, 16
lui a0, %hi(std::__ioinit)
addi a0, a0, %lo(std::__ioinit)
sw a0, -12(s0)
call std::ios_base::Init::Init() [complete object constructor]
lw a1, -12(s0)
lui a0, %hi(_ZNSt8ios_base4InitD1Ev)
addi a0, a0, %lo(_ZNSt8ios_base4InitD1Ev)
lui a2, %hi(__dso_handle)
addi a2, a2, %lo(__dso_handle)
call __cxa_atexit
lw s0, 8(sp)
lw ra, 12(sp)
addi sp, sp, 16
ret
main:
addi sp, sp, -48
sw ra, 44(sp)
sw s0, 40(sp)
addi s0, sp, 48
mv a0, zero
sw a0, -36(s0)
sw a0, -12(s0)
addi a0, s0, -32
sw a0, -40(s0)
call Derived::Derived() [base object constructor]
lw a0, -40(s0)
call Base::show1()
lw a0, -36(s0)
lw s0, 40(sp)
lw ra, 44(sp)
addi sp, sp, 48
ret
Derived::Derived() [base object constructor]:
addi sp, sp, -16
sw ra, 12(sp)
sw s0, 8(sp)
addi s0, sp, 16
sw a0, -12(s0)
lw a0, -12(s0)
sw a0, -16(s0)
call Base::Base() [base object constructor]
lw a1, -16(s0)
lui a0, %hi(vtable for Derived)
addi a0, a0, %lo(vtable for Derived)
addi a0, a0, 8
sw a0, 0(a1)
addi a0, zero, 3
sw a0, 12(a1)
lw s0, 8(sp)
lw ra, 12(sp)
addi sp, sp, 16
ret
Base::show1():
addi sp, sp, -16
sw ra, 12(sp)
sw s0, 8(sp)
addi s0, sp, 16
sw a0, -12(s0)
lw a0, -12(s0)
lw a1, 4(a0)
lui a0, %hi(_ZSt4cout)
addi a0, a0, %lo(_ZSt4cout)
call std::ostream::operator<<(int)
lui a1, %hi(_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_)
addi a1, a1, %lo(_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_)
call std::ostream::operator<<(std::ostream& (*)(std::ostream&))
lw s0, 8(sp)
lw ra, 12(sp)
addi sp, sp, 16
ret
Base::Base() [base object constructor]:
addi sp, sp, -16
sw ra, 12(sp)
sw s0, 8(sp)
addi s0, sp, 16
sw a0, -12(s0)
lw a1, -12(s0)
lui a0, %hi(vtable for Base)
addi a0, a0, %lo(vtable for Base)
addi a0, a0, 8
sw a0, 0(a1)
addi a0, zero, 1
sw a0, 4(a1)
addi a0, zero, 2
sw a0, 8(a1)
lw s0, 8(sp)
lw ra, 12(sp)
addi sp, sp, 16
ret
Derived::show2():
addi sp, sp, -16
sw ra, 12(sp)
sw s0, 8(sp)
addi s0, sp, 16
sw a0, -12(s0)
lw a0, -12(s0)
lw a1, 4(a0)
lui a0, %hi(_ZSt4cout)
addi a0, a0, %lo(_ZSt4cout)
call std::ostream::operator<<(int)
lui a1, %hi(_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_)
addi a1, a1, %lo(_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_)
call std::ostream::operator<<(std::ostream& (*)(std::ostream&))
lw s0, 8(sp)
lw ra, 12(sp)
addi sp, sp, 16
ret
Base::show2():
addi sp, sp, -16
sw ra, 12(sp)
sw s0, 8(sp)
addi s0, sp, 16
sw a0, -12(s0)
lw a0, -12(s0)
lw a1, 4(a0)
lui a0, %hi(_ZSt4cout)
addi a0, a0, %lo(_ZSt4cout)
call std::ostream::operator<<(int)
lui a1, %hi(_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_)
addi a1, a1, %lo(_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_)
call std::ostream::operator<<(std::ostream& (*)(std::ostream&))
lw s0, 8(sp)
lw ra, 12(sp)
addi sp, sp, 16
ret
_GLOBAL__sub_I_example.cpp:
addi sp, sp, -16
sw ra, 12(sp)
sw s0, 8(sp)
addi s0, sp, 16
call __cxx_global_var_init
lw s0, 8(sp)
lw ra, 12(sp)
addi sp, sp, 16
ret
std::__ioinit:
.zero 1
vtable for Derived:
.word 0
.word typeinfo for Derived
.word Base::show1()
.word Derived::show2()
typeinfo name for Derived:
.asciz "7Derived"
typeinfo name for Base:
.asciz "4Base"
typeinfo for Base:
.word _ZTVN10__cxxabiv117__class_type_infoE+8
.word typeinfo name for Base
typeinfo for Derived:
.word _ZTVN10__cxxabiv120__si_class_type_infoE+8
.word typeinfo name for Derived
.word typeinfo for Base
vtable for Base:
.word 0
.word typeinfo for Base
.word Base::show1()
.word Base::show2()
行为分析
有虚函数的话,对象的首地址就会设置为虚函数表的位置,然后父类设置之后子类再设置覆盖掉。
纯虚函数
源码
#include <iostream>
using namespace std;
class Base {
public:
int a,b;
Base(){
a=1;
b=2;
}
virtual void show1(){
cout<<a<<endl;
}
virtual void show2()=0;
};
// 子类
class Derived : public Base {
public:
int c;
Derived(){
c=3;
}
virtual void show2(){
cout<<a<<endl;
}
};
int main() {
Derived b ;
b.show1();
return 0;
}
汇编
__cxx_global_var_init:
addi sp, sp, -16
sw ra, 12(sp)
sw s0, 8(sp)
addi s0, sp, 16
lui a0, %hi(std::__ioinit)
addi a0, a0, %lo(std::__ioinit)
sw a0, -12(s0)
call std::ios_base::Init::Init() [complete object constructor]
lw a1, -12(s0)
lui a0, %hi(_ZNSt8ios_base4InitD1Ev)
addi a0, a0, %lo(_ZNSt8ios_base4InitD1Ev)
lui a2, %hi(__dso_handle)
addi a2, a2, %lo(__dso_handle)
call __cxa_atexit
lw s0, 8(sp)
lw ra, 12(sp)
addi sp, sp, 16
ret
main:
addi sp, sp, -48
sw ra, 44(sp)
sw s0, 40(sp)
addi s0, sp, 48
mv a0, zero
sw a0, -36(s0)
sw a0, -12(s0)
addi a0, s0, -32
sw a0, -40(s0)
call Derived::Derived() [base object constructor]
lw a0, -40(s0)
call Base::show1()
lw a0, -36(s0)
lw s0, 40(sp)
lw ra, 44(sp)
addi sp, sp, 48
ret
Derived::Derived() [base object constructor]:
addi sp, sp, -16
sw ra, 12(sp)
sw s0, 8(sp)
addi s0, sp, 16
sw a0, -12(s0)
lw a0, -12(s0)
sw a0, -16(s0)
call Base::Base() [base object constructor]
lw a1, -16(s0)
lui a0, %hi(vtable for Derived)
addi a0, a0, %lo(vtable for Derived)
addi a0, a0, 8
sw a0, 0(a1)
addi a0, zero, 3
sw a0, 12(a1)
lw s0, 8(sp)
lw ra, 12(sp)
addi sp, sp, 16
ret
Base::show1():
addi sp, sp, -16
sw ra, 12(sp)
sw s0, 8(sp)
addi s0, sp, 16
sw a0, -12(s0)
lw a0, -12(s0)
lw a1, 4(a0)
lui a0, %hi(_ZSt4cout)
addi a0, a0, %lo(_ZSt4cout)
call std::ostream::operator<<(int)
lui a1, %hi(_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_)
addi a1, a1, %lo(_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_)
call std::ostream::operator<<(std::ostream& (*)(std::ostream&))
lw s0, 8(sp)
lw ra, 12(sp)
addi sp, sp, 16
ret
Base::Base() [base object constructor]:
addi sp, sp, -16
sw ra, 12(sp)
sw s0, 8(sp)
addi s0, sp, 16
sw a0, -12(s0)
lw a1, -12(s0)
lui a0, %hi(vtable for Base)
addi a0, a0, %lo(vtable for Base)
addi a0, a0, 8
sw a0, 0(a1)
addi a0, zero, 1
sw a0, 4(a1)
addi a0, zero, 2
sw a0, 8(a1)
lw s0, 8(sp)
lw ra, 12(sp)
addi sp, sp, 16
ret
Derived::show2():
addi sp, sp, -16
sw ra, 12(sp)
sw s0, 8(sp)
addi s0, sp, 16
sw a0, -12(s0)
lw a0, -12(s0)
lw a1, 4(a0)
lui a0, %hi(_ZSt4cout)
addi a0, a0, %lo(_ZSt4cout)
call std::ostream::operator<<(int)
lui a1, %hi(_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_)
addi a1, a1, %lo(_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_)
call std::ostream::operator<<(std::ostream& (*)(std::ostream&))
lw s0, 8(sp)
lw ra, 12(sp)
addi sp, sp, 16
ret
_GLOBAL__sub_I_example.cpp:
addi sp, sp, -16
sw ra, 12(sp)
sw s0, 8(sp)
addi s0, sp, 16
call __cxx_global_var_init
lw s0, 8(sp)
lw ra, 12(sp)
addi sp, sp, 16
ret
std::__ioinit:
.zero 1
vtable for Derived:
.word 0
.word typeinfo for Derived
.word Base::show1()
.word Derived::show2()
typeinfo name for Derived:
.asciz "7Derived"
typeinfo name for Base:
.asciz "4Base"
typeinfo for Base:
.word _ZTVN10__cxxabiv117__class_type_infoE+8
.word typeinfo name for Base
typeinfo for Derived:
.word _ZTVN10__cxxabiv120__si_class_type_infoE+8
.word typeinfo name for Derived
.word typeinfo for Base
vtable for Base:
.word 0
.word typeinfo for Base
.word Base::show1()
.word __cxa_pure_virtual
行为分析
抽象类的虚函数表里标注了纯虚函数,这里是找不到base的show2实现的
vtable for Base:
.word 0
.word typeinfo for Base
.word Base::show1()
.word __cxa_pure_virtual
行为和没有纯虚函数一样,也是替换表
多态
源码
#include <iostream>
using namespace std;
class Base {
public:
int a,b;
Base(){
a=1;
b=2;
}
virtual void show2(){
cout<<a<<endl;
}
virtual void show1(){
cout<<a<<endl;
}
};
// 子类
class Derived : public Base {
public:
int c;
Derived(){
c=3;
}
virtual void show2(){
cout<<a<<endl;
}
virtual void show3(){
cout<<a<<endl;
}
};
// 修正后的函数
void callShow2(Base* x){
x->show2();
}
int main() {
Derived b ;
b.show1();
callShow2(&b); // 调用修正后的函数来展示 show2 的效果
return 0;
}
汇编
__cxx_global_var_init:
addi sp, sp, -16
sw ra, 12(sp)
sw s0, 8(sp)
addi s0, sp, 16
lui a0, %hi(std::__ioinit)
addi a0, a0, %lo(std::__ioinit)
sw a0, -12(s0)
call std::ios_base::Init::Init() [complete object constructor]
lw a1, -12(s0)
lui a0, %hi(_ZNSt8ios_base4InitD1Ev)
addi a0, a0, %lo(_ZNSt8ios_base4InitD1Ev)
lui a2, %hi(__dso_handle)
addi a2, a2, %lo(__dso_handle)
call __cxa_atexit
lw s0, 8(sp)
lw ra, 12(sp)
addi sp, sp, 16
ret
callShow2(Base*):
addi sp, sp, -16
sw ra, 12(sp)
sw s0, 8(sp)
addi s0, sp, 16
sw a0, -12(s0)
lw a0, -12(s0)
lw a1, 0(a0)
lw a1, 0(a1)
jalr a1
lw s0, 8(sp)
lw ra, 12(sp)
addi sp, sp, 16
ret
main:
addi sp, sp, -48
sw ra, 44(sp)
sw s0, 40(sp)
addi s0, sp, 48
mv a0, zero
sw a0, -36(s0)
sw a0, -12(s0)
addi a0, s0, -32
sw a0, -40(s0)
call Derived::Derived() [base object constructor]
lw a0, -40(s0)
call Base::show1()
lw a0, -40(s0)
call callShow2(Base*)
lw a0, -36(s0)
lw s0, 40(sp)
lw ra, 44(sp)
addi sp, sp, 48
ret
Derived::Derived() [base object constructor]:
addi sp, sp, -16
sw ra, 12(sp)
sw s0, 8(sp)
addi s0, sp, 16
sw a0, -12(s0)
lw a0, -12(s0)
sw a0, -16(s0)
call Base::Base() [base object constructor]
lw a1, -16(s0)
lui a0, %hi(vtable for Derived)
addi a0, a0, %lo(vtable for Derived)
addi a0, a0, 8
sw a0, 0(a1)
addi a0, zero, 3
sw a0, 12(a1)
lw s0, 8(sp)
lw ra, 12(sp)
addi sp, sp, 16
ret
Base::show1():
addi sp, sp, -16
sw ra, 12(sp)
sw s0, 8(sp)
addi s0, sp, 16
sw a0, -12(s0)
lw a0, -12(s0)
lw a1, 4(a0)
lui a0, %hi(_ZSt4cout)
addi a0, a0, %lo(_ZSt4cout)
call std::ostream::operator<<(int)
lui a1, %hi(_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_)
addi a1, a1, %lo(_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_)
call std::ostream::operator<<(std::ostream& (*)(std::ostream&))
lw s0, 8(sp)
lw ra, 12(sp)
addi sp, sp, 16
ret
Base::Base() [base object constructor]:
addi sp, sp, -16
sw ra, 12(sp)
sw s0, 8(sp)
addi s0, sp, 16
sw a0, -12(s0)
lw a1, -12(s0)
lui a0, %hi(vtable for Base)
addi a0, a0, %lo(vtable for Base)
addi a0, a0, 8
sw a0, 0(a1)
addi a0, zero, 1
sw a0, 4(a1)
addi a0, zero, 2
sw a0, 8(a1)
lw s0, 8(sp)
lw ra, 12(sp)
addi sp, sp, 16
ret
Derived::show2():
addi sp, sp, -16
sw ra, 12(sp)
sw s0, 8(sp)
addi s0, sp, 16
sw a0, -12(s0)
lw a0, -12(s0)
lw a1, 4(a0)
lui a0, %hi(_ZSt4cout)
addi a0, a0, %lo(_ZSt4cout)
call std::ostream::operator<<(int)
lui a1, %hi(_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_)
addi a1, a1, %lo(_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_)
call std::ostream::operator<<(std::ostream& (*)(std::ostream&))
lw s0, 8(sp)
lw ra, 12(sp)
addi sp, sp, 16
ret
Derived::show3():
addi sp, sp, -16
sw ra, 12(sp)
sw s0, 8(sp)
addi s0, sp, 16
sw a0, -12(s0)
lw a0, -12(s0)
lw a1, 4(a0)
lui a0, %hi(_ZSt4cout)
addi a0, a0, %lo(_ZSt4cout)
call std::ostream::operator<<(int)
lui a1, %hi(_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_)
addi a1, a1, %lo(_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_)
call std::ostream::operator<<(std::ostream& (*)(std::ostream&))
lw s0, 8(sp)
lw ra, 12(sp)
addi sp, sp, 16
ret
Base::show2():
addi sp, sp, -16
sw ra, 12(sp)
sw s0, 8(sp)
addi s0, sp, 16
sw a0, -12(s0)
lw a0, -12(s0)
lw a1, 4(a0)
lui a0, %hi(_ZSt4cout)
addi a0, a0, %lo(_ZSt4cout)
call std::ostream::operator<<(int)
lui a1, %hi(_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_)
addi a1, a1, %lo(_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_)
call std::ostream::operator<<(std::ostream& (*)(std::ostream&))
lw s0, 8(sp)
lw ra, 12(sp)
addi sp, sp, 16
ret
_GLOBAL__sub_I_example.cpp:
addi sp, sp, -16
sw ra, 12(sp)
sw s0, 8(sp)
addi s0, sp, 16
call __cxx_global_var_init
lw s0, 8(sp)
lw ra, 12(sp)
addi sp, sp, 16
ret
std::__ioinit:
.zero 1
vtable for Derived:
.word 0
.word typeinfo for Derived
.word Derived::show2()
.word Base::show1()
.word Derived::show3()
typeinfo name for Derived:
.asciz "7Derived"
typeinfo name for Base:
.asciz "4Base"
typeinfo for Base:
.word _ZTVN10__cxxabiv117__class_type_infoE+8
.word typeinfo name for Base
typeinfo for Derived:
.word _ZTVN10__cxxabiv120__si_class_type_infoE+8
.word typeinfo name for Derived
.word typeinfo for Base
vtable for Base:
.word 0
.word typeinfo for Base
.word Base::show2()
.word Base::show1()
行为分析
首先观察表,子类是肯定包含了父类的所有虚函数的,只是会把重新实现的,替换为自己的,所以体现多态就是这样,我们传入参数是基类指针,因为默认的虚函数表是在首地址的,大家都一样,然后我们都想调用show2(),因为穿进来的指针指向的地址拿到的虚函数表是不一样的,虽然偏移一样,但是最后调用的就是不同的虚函数实现。
为什么构造函数不能是虚函数
由之前的行为分析知道,子类实例化过程中,会去调用父类的构造函数,将对象的首地址设置为父类的虚函数表,再去设置父类的成员变量,再退回到子类构造函数重复一样的操作。
对于虚函数,是为了覆盖父类的行为实现多态,那么假设构造是虚函数,怎么去覆盖父类的构造行为,虚函数的;
进一步将,子类的行为是,调用父类构造,然后覆盖他的虚函数表,然后父类构造变成了子类构造,这完全乱套。
所以来说,构造根本就和多态不是一个东西,混在一起完全没有意义,他只是帮助设置初值和虚函数表的,与多态行为无关。