C++ 多态相关
文章目录
- 1. 静态类型和动态类型
- 1.1 静态类型:对象定义时的类型,编译期间就确定好的。
- 1.2 动态类型:对象目前所指向的类型(运行的时候才决定类型的)。
- 2. 静态绑定和动态绑定
- 3. 继承的非虚函数坑
- 4. 虚函数的动态绑定
- 5. 重新定义虚函数缺省参数(坑)
- 6 C++ 中的多态性
1. 静态类型和动态类型
1.1 静态类型:对象定义时的类型,编译期间就确定好的。
静态类型是指在编译时就能确定的数据类型或变量的类型
如下代码
#include <iostream>
class Base
{};
class Derive : public Base
{};
class Derive2 : public Base
{};
class Derive3 : public Base
{};
int main()
{
Base base; //静态类型是 Base
Derive derive; //静态类型是 Derive
Base* pbase = nullptr;; //无论指向父类还是子类,定义时类型为 Base*,静态类型Base*
Base* pbase2 = new Derive2(); //静态类型依然是 Base*
Base* pbase3 = new Derive3(); //静态类型依然是 Base*
}
Base base; //静态类型是 Base
Derive derive; //静态类型是 Derive
Base* pbase = nullptr ; // 无论指向父类还是子类,定义时类型为 Base* ,静态类型是Base*
Base* pbase2 = new Derive2(); //静态类型依然是 Base*
Base* pbase3 = new Derive3(); //静态类型依然是 Base*
1.2 动态类型:对象目前所指向的类型(运行的时候才决定类型的)。
一般来讲,只有指针或者引用才有动态类型的说法,而且一般都是指父类的指针或者引用。
动态类型描述指针所指向的对象的实际类型
动态类型描述引用,指的是该引用当前所绑定对象的实际类型。
代码如下
#include <iostream>
class Base
{};
class Derive : public Base
{};
class Derive2 : public Base
{};
class Derive3 : public Base
{};
int main()
{
Base base; //静态类型是 Base
Derive derive; //静态类型是 Derive
Base* pbase = nullptr;; // 无论指向父类还是子类定义时 Base* ,静态类型是Base*
Base* pbase2 = new Derive2(); //静态类型依然是 Base*
Base* pbase3 = new Derive3(); //静态类型依然是 Base*
}
- base 和 derive
没有动态类型
,因为他们既不是指针也不是引用 - pbase 也没有动态类型,因为他没有指向任何对象.
- pbase2 有动态类型,指向的对象的动态类型是 Derive2.
- pbase3 有动态类型,指向的对象的动态类型是 Derive3.
动态类型在执行过程中可以改变,如下
pbase = pbase2; //指向的对象的动态类型是 Derive2
pbase = pbase3; //指向的对象的动态类型是 Derive3
2. 静态绑定和动态绑定
静态绑定
: 绑定的是静态类型,所对应的函数或属性依赖于对象的静态类型,发生在编译期.
动态绑定
: 绑定的是动态类型,所对应的函数或属性依赖于对象的动态类型,发生在运行期.
- 普通成员函数是静态绑定,而虚函数是动态绑定。
- 缺省参数一般是静态绑定
3. 继承的非虚函数坑
代码如下
#include <iostream>
class Base
{
public:
void myfunc()
{
std::cout << "Base::myfunc()" << std::endl;
}
};
class Derive : public Base
{
public:
void myfunc()
{
std::cout << "Derive::myfunc()" << std::endl;
}
};
int main()
{
Derive derive;
Derive* pderive = &derive;
pderive->myfunc(); //Derive::myfunc()
Base* pbase = &derive;
pbase->myfunc(); //Base::myfunc()
return 0;
}
可得:
普通成员函数是静态绑定, 执行myfunc()取决于调用者的静态类型. pderive的静态类型是Derive*
,所以调用的是Derive的myfunc()
, pbase的静态类型是Base*
,调用的是Base的myfunc()
。
4. 虚函数的动态绑定
代码如下
#include <iostream>
class Base
{
public:
virtual void myvirfunc()
{
std::cout << "Base::myvirfunc()" << std::endl;
}
};
class Derive : public Base
{
public:
virtual void myvirfunc()
{
std::cout << "Derive::myvirfunc()" << std::endl;
}
};
int main()
{
Derive derive;
Base base;
Derive* pderive = &derive;
Base* pbase = &derive;
pderive->myvirfunc(); //Derive::myvirfunc()
pbase->myvirfunc(); //Derive::myvirfunc()
pbase = &base;
pbase->myvirfunc(); //Base::myvirfunc()
return 0;
}
可得:
虚函数是动态绑定,pbase指向的对象的动态类型开始是 Derive
调用的是Derive的myvirfunc()
后来pbase指向的对象的动态类型变为Base
,调用的是Base的myvirfunc()。
5. 重新定义虚函数缺省参数(坑)
代码如下
#include <iostream>
class Base
{
public:
virtual void myvirfunc(int value = 1)
{
std::cout << "Base::myvirfunc(), value = " << value << std::endl;
}
};
class Derive : public Base
{
public:
virtual void myvirfunc(int value = 2)
{
std::cout << "Derive::myvirfunc(), value = " << value << std::endl;
}
};
int main()
{
Derive derive;
Base base;
Derive* pderive = &derive;
Base* pbase = &derive;
pderive->myvirfunc(); //Derive::myvirfunc()
pbase->myvirfunc(); //Derive::myvirfunc()
pbase = &base;
pbase->myvirfunc(); //Base::myvirfunc()
return 0;
}
Derive derive;
Base* pbase = &derive;
pbase->myvirfunc(); //Derive::myvirfunc()
观察:
执行子类的虚函数,但输出形参value的值确实是父类虚函数形参的缺省值
可得:
缺省参数是静态绑定的(pbase的静态类型是Base*)
绑定到Base对应myvirfunc()的缺省参数上。
注意:
不要在子类中重新定义虚函数缺省参数的值
6 C++ 中的多态性
多态必须存在虚函数并且调用虚函数,没有虚函数,多态不存在
- 从代码实现上
- 当调用虚函数时,调用路线是通过查询虚函数表找到虚函数入口然后调用
- 从表现形式上看
- 父类子类存在继承关系,父类中含有虚函数子类重写父类中的虚函数
- 父类指针(引用)指向子类对象
- 父类的指针(引用)调用子类重写的虚函数