一、静态多态
静态多态:编译器在编译期间完成的,编译器根据函数实参的类型(可能会进行隐式类型转换),可推
断出要调用那个函数,如果有对应的函数就调用该函数,否则出现编译错误。
#include <iostream>
using namespace std;
int add(int right, int left)
{
return right + left;
}
float add(float right, float left)
{
return right + left;
}
template <class T>
T sub(T right, T left)
{
return right - left;
}
int main()
{
add(1, 2);
add(1.0f, 2.0f);
sub(3, 1);
sub(1.0, 3.0);
system("pause");
return 0;
}
动态绑定:在程序执行期间(非编译期)判断所引用对象的实际类型,根据其实际类型调用相应的方
法。
使用virtual关键字修饰类的成员函数时,指明该函数为虚函数,派生类需要重新实现,编译器将实
现动态绑定。
动态绑定条件:
1、虚函数: 在派生类中必须对基类虚函数进行重写
2、调用虚函数的方式:必须通过基类的指针或引用
重写(覆盖):在继承体系中,如果基类中有虚函数,在派生类中,函数名相同(析构函数例外),参数相同
,返回值相同(协变例外)
#include <iostream>
using namespace std;
class B
{
public:
virtual void Test1(int a)
{
cout << "B::Test1()" << endl;
}
virtual void Test2(int b)
{
cout << "B::Test12()" << endl;
}
virtual ~B()
{
cout << "~B()" << endl;
}
};
class D :public B
{
public:
virtual void Test1(int a)
{
cout << "D::Test1()" << endl;
}
virtual void Test2(int b)
{
cout << "D::Test2()" << endl;
}
virtual ~D()
{
cout << "~D()" << endl;
}
};
void FunTest(B& b)
{
b.Test1(1);
b.Test2(2);
b.~B();
}
int main()
{
D d;
B b;
FunTest(d);
FunTest(b);
system("pause");
return 0;
}
纯虚函数:在成员函数的形参列表后面写上=0,则成员函数为纯虚函数。包含纯虚函数的类叫做抽象类(也
叫接口类),抽象类不能实例化出对象。纯虚函数在派生类中重新定义以后,派生类才能实例化出对
象。
虚表:
#include <iostream>
using namespace std;
class B
{
public:
virtual void Test()
{}
};
int main()
{
B b;
sizeof(b);
b.Test();
system("pause");
return 0;
}
调试上述代码:
的对于有虚函数的类,编译器都会维护一张虚表,对象的前四个字节就是指向虚表的指针
虚表指针实际上是函数指针数组的指针
基类中的虚表:按照虚函数的声明次序存放
单继承下派生类的虚表:
1.先将基类的虚表拷贝一份
2、检测派生类中是不是对其基类中的虚函数进行重写,如果构成重写派生类重写的虚函数来替换相同偏移量位置的基类虚函数
3、将自己独有的虚函数放在后面
多继承下的虚表:
先继承的基类虚表在前,派生类独有的在第一张虚表之后
#include <iostream>
using namespace std;
class B
{
public:
virtual void Test1(int a)
{
cout << "B::Test1()" << endl;
}
virtual void Test2(int b)
{
cout << "B::Test2()" << endl;
}
virtual void Test3(int b)
{
cout << "B::Test13()" << endl;
}
virtual ~B()
{
cout << "~B()" << endl;
}
};
class D :public B
{
public:
virtual void Test1(int a)
{
cout << "D::Test1()" << endl;
}
virtual void Test2(int b)
{
cout << "D::Test2()" << endl;
}
virtual void Test3()
{
cout << "D::Test3()" << endl;
}
virtual ~D()
{
cout << "~D()" << endl;
}
};
typedef void(*Func)(int);
void FunC(B& b)
{
Func* pfun = (Func *)(*(int*)(&b));//取虚表的地址
(*pfun)(1);
}
void FunC(D& d)
{
Func* pfun = (Func *)(*(int*)(&d));
(*pfun)(1);
}
void FunC1(B& b)
{
Func* pfun = (Func *)(*(int*)(&b));
(*(pfun + 1))(1);
}
void FunC1(D& d)
{
Func* pfun = (Func *)(*(int*)(&d));
(*(pfun + 1))(1);
}
void FunC2(B& b)
{
Func* pfun = (Func *)(*(int*)(&b));
(*(pfun + 2))(1);
}
void FunC2(D& d)
{
Func* pfun = (Func *)(*(int*)(&d));
(*(pfun + 2))(1);
}
D d;
B b;
void Test1()
{
FunC(b);
}
void Test2()
{
FunC(d);
}
void Test3()
{
FunC1(b);
}
void Test4()
{
FunC1(d);
}
int main()
{
cout << sizeof(d) << endl;
cout << sizeof(b) << endl;
/*Test1();*/
/*Test2();*/
/*Test3();*/
Test4();
system("pause");
return 0;
}
分别打印b和d的虚函数 b ,d 大小都为4个字节
带虚函数的虚拟菱形继承
#include <iostream>
using namespace std;
class B
{
public:
virtual void Test1(int a)
{
cout << "B::Test1()" << endl;
}
virtual void Test2(int b)
{
cout << "B::Test2()" << endl;
}
int _b;
};
class C1 :virtual public B
{
public:
virtual void Test1(int a)
{
cout << "C1::Test1()" << endl;
}
virtual void Test3(int b)
{
cout << "C1::Test3()" << endl;
}
int _c1;
};
class C2 :virtual public B
{
public:
virtual void Test1(int a)
{
cout << "C2::Test1()" << endl;
}
virtual void Test4(int b)
{
cout << "C2::Test4()" << endl;
}
int _c2;
};
class D :public C1, public C2
{
public:
virtual void Test1(int a)
{
cout << "D::Test1()" << endl;
}
virtual void Test2(int b)
{
cout << "D::Test2()" << endl;
}
virtual void Test3()
{
cout << "D::Test3()" << endl;
}
int _d;
};
typedef void(*Func)(int);
void FunC(D& d)
{
Func* pfun = (Func *)(*(int*)(&d));//C1虚表地址
(*pfun)(1);
}
void FunC1(D& d)
{
Func* pfun = (Func *)(*((int*)(&d) + 3));//C2虚表地址
(*(pfun))(1);
}
void FunC2(D& d)
{
Func* pfun = (Func *)(*((int*)(&d) + 7));// B 虚表地址
(*(pfun))(1);
}
int main()
{
D d;
cout << sizeof(d) << endl;
d._b = 1;
d._c1 = 2;
d._c2 = 3;
d._d = 4;
/*FunC(d);*/
/*FunC1(d);*/
/*FunC2(d);*/
system("pause");
return 0;
}
那么多的字节放的什么东西呢?
重新运行了一次,所以地址不一样
d的对象模型为: