(1).对象类型:
a.静态类型:对象声明时的类型,编译的时候确定
b.动态类型:对象的类型是运行时才能确定的
class A {}; class B:public A {}; int main() { B* b; A* a=b;//a的静态类型是A*,动态类型(运行时)类型是B* return 0; }
(2).多态
a.静态多态:函数重载、泛性编程
int Add(int a,int b) { return a+b; } float Add(float a,float b) { return a+b; } int main() { cout<<Add(10,20)<<endl;; cout<<Add(10.1f,20.2f)<<endl;; return 0; } 在编译期间,编译器会根据函数实参的类型推断要调用那个函数
b.动态多态:虚函数
1>.每个类都维护这一张虚表;调用虚函数查看对象是那个类,然后查表
2>.基类可以使用为纯虚函数(virtual void fun()=0),基类就是抽象类要求子类实现
虚函数:
含有虚函数或其父类含有虚函数的类,编译器都会为其添加一个虚函数表,vptr,
虚基类表:虚继承产生虚基类表(vbptr),虚基表的内容与虚基表完全不同
**1**、单继承
1)子类重写父类虚函数:
class A { public: virtual void fun() { cout<<"A-fun()"<<endl; } A() {} ~A() {} private: int a1; }; class B:public A { public: void fun() { cout<<"B-fun()"<<endl; } B() {} ~B() {} private: int b1; };
2)子类定义了新的虚函数:
class A { public: virtual void fun() { cout<<"A-fun()"<<endl; } A() {} ~A() {} private: int a1; }; class B:public A { public: virtual void fun1() { cout<<"B-fun()"<<endl; } B() {} ~B() {} private: int b1; };
**2**、多继承
1)子类重写父类虚函数
class A { public: virtual void Afun() {} private: int a1; }; class B { public: virtual void Bfun() {} private: int b1; }; class C:public A,public B { public: void Afun() {} void Bfun() {} private: int c1; }; int main() { A a; B b; C c; cout<<sizeof(a)<<endl; cout<<(int*)(&a)<<endl; cout<<sizeof(b)<<endl; cout<<(int*)(&b)<<endl; cout<<sizeof(c)<<endl; cout<<(int*)(&c)<<endl; return 0; }
2)子类定义新的虚函数
class A { public: virtual void Afun() {} private: int a1; }; class B { public: virtual void Bfun() {} private: int b1; }; class C:public A,public B { public: virtual void Cfun() {} private: int c1; }; int main() { A a; B b; C c; cout<<sizeof(a)<<endl; cout<<(int*)(&a)<<endl; cout<<sizeof(b)<<endl; cout<<(int*)(&b)<<endl; cout<<sizeof(c)<<endl; cout<<(int*)(&c)<<endl; return 0; }
3) 菱形继承
class A { public: void Afun() { cout<<"Afun()"<<endl; } A() {} ~A() {} private: int a1; }; class B:public A { public: void Bfun() { cout<<"Bfun()"<<endl; } B() {} ~B() {} private: int b1; }; class C:public A { public: void Cfun() { cout<<"Cfun()"<<endl; } private: int c1; }; class D:public B,public C { public: void Dfun() { cout<<"D-fun()"<<endl; } private: int d1; };
**3**、虚继承(解决了菱形继承数据冗余和二义性的问题)(虚继承对应要有虚类指针)
1)单一继承下的虚继承
class A { public: virtual void Afun() {} private: int a1; }; class B:virtual public A { public: void Afun() {} private: int b1; }; 给B实例化一个对象,它的大小是16,是因为在虚继承过程中,会出现对应的虚类指针
***虚函数的主要作用是为了实现多态机制
class Base { virtual void print(void); }; class Drive1:public Base { virtual void print(void); }; class Drive2:public Base { virtual void print(void); }; int main(int argc,char* argv[]) { Base* ptr1=new Base; Base* ptr2=new Drive1; Base* ptr3=new Drive2; ptr1->print();//调用base::print() ptr2->print();//调用Drive1::print() ptr3->print();//调用Drive2::print() return 0; }这是一种运行期多态,父类指针唯有在程序运行时才能知道所致的真正类型是什么,这种运行期决议是通过虚函数表来实现的
***使用指针访问虚表
class Base { public: Base(int i) :base1(i) {} virtual void print(void) { cout<<"Base::print()"<<endl; } virtual void setl(void) { cout<<"Base::setl"<<endl; } virtual ~Base() {} private: int base1; }; int main(int argc,char* argv[]) { Base b(1000); int* vptrAdree=(int*)(&b); cout<<"虚函数指针(vptr)的地址是: "<<vptrAdree<<endl; return 0; } 当一个类本身定义了虚函数或者其父类有虚函数时,为了支持多态机制,编译器为该类添加了一个虚函数指针(vptr),虚函数指针一般放在对象内存布局的第一个位置上,这是为了保证在多层继承或多重继承的情况下能以最高效率取到虚表 这个代码的mian()里我们取到了虚函数的地址(vptrAdree),虚函数指针指向虚函数表,虚函数表存的是一系列虚函数的地址,虚函数地址出现的顺序与类中虚函数声明的顺序一致