71.静态类型和动态类型,静态绑定和动态绑定的介绍

71.静态类型和动态类型,静态绑定和动态绑定的介绍

在C++中,变量的类型可以分为静态类型和动态类型两种。

1.类型

静态类型:静态类型是指在程序运行时分配的类型,它们的大小和数据结构在程序运行时就已经确定了,因此可以直接使用int、float等基本数据类型或者自定义数据类型。静态类型的变量可以通过直接赋值或者引用的方式来传递它们的值,不需要使用new/delete运算符进行动态分配和释放。

动态类型:动态类型是指在程序运行时分配的类型,它们的大小和数据结构在程序运行时可以改变,通常是通过new/delete运算符来动态分配的。动态类型的变量需要使用new/delete运算符来创建和销毁,而且它们的值传递需要使用指针或者引用的方式,而不能直接使用变量名称来访问。指针或者引用所代表的内存中的对象的类型,在运行阶段才可以确定。

GameObject* pgo = new SpaceShip // pgo 静态类型是 GameObject*, 动态类型是 SpaceShip*
Asterioid * pa = new Asterioid;  // pa 的静态类型是 Asterioid *, 动态类型也是 Asterioid *
pgo = pa;                       // pgo 静态类型总指向 GameObject *, 动态类型指向 Asterioid *
GameObject& rgo = *pa;          // rgo 的静态类型是 GameObject, 动态类型是 Asterioid
class B
{
}
class C : public B
{
}
class D : public B
{
}
D* pD = new D();//pD的静态类型是它声明的类型D*,动态类型也是D*
B* pB = pD;//pB的静态类型是它声明的类型B*,动态类型是pB所指向的对象pD的类型D*
C* pC = new C();
pB = pC;//pB的动态类型是可以更改的,现在它的动态类型是C*

2.绑定

  • 静态绑定绑定的是对象的静态类型,某特性(比如函数)依赖于对象的静态类型,发生在编译期,又称前期绑定 early binding;

  • 动态绑定绑定的是对象的动态类型,某特性(比如函数)依赖于对象的动态类型,发生在运行期,又称后期绑定 late binding;

2.1虚函数与作用域

class Base
{
public:
	virtual int fcn();
};

class D1 :public Base
{
public:
	//隐藏基类的fcn,这个fcn不是虚函数
	//D1继承了Base::fcn()的定义
	int fcn(int);//形参列表于Base中的fcn不一致
	virtual void f2();//是一个新的虚函数,在Base中不存在
};

class D2 :public D1
{
public:
	int fcn(int);//是一个非虚函数,隐藏了D1::fcn(int)
	int fcn();//覆盖了Base的虚函数fcn
	void f2();
};

隐藏:在子类中有与父类中同名的成员函数,当父类中同名成员函数为虚函数,但形参列表不一致时(也即未发生函数重载),或者父类同名函数非虚函数,子类未重载其父类同名成员函数,父类的同名成员函数被隐藏。

覆盖(存在虚函数是前提):在子类中有与父类中同名的成员函数,当父类中同名成员函数为虚函数且形参列表一致时(也即发生函数重载),父类的同名成员函数被覆盖。

2.2通过基类调用隐藏的虚函数

Base bobj; D1 d1obj; D2 d2obj;

Base* bp1 = &bobj, * bp2 = &d1obj, * bp3 = &d2obj;
bp1->fcn();//虚调用,将在运行时调用Base::fcn
bp2->fcn();//虚调用,将在运行时调用Base::fcn
bp3->fcn();//虚调用,将在运行时调用D2::fcn

D1* d1p = &d1obj; D2* d2p = &d2obj;
bp2->f2();//错误:Base没有名为f2的成员
d1p->f2();//虚调用,将在运行时调用D1::f2()
d2p->f2();//虚调用,将在运行时调用D2::f2()

Base* p1 = &d2obj; D1* p2 = &d2obj; D2 *p3 = &d2obj;
p1->fcn(42);//错误:Base中没有接受一个int的fcn
p2->fcn(42);//静态绑定,调用D1::fcn(int)
p3->fcn(42);//静态绑定,调用D2::fcn(int)

前三条调用语句是通过基类的指针进行的,因为fcn是虚函数,所以编译器产生的代码将在运行时确定使用虚函数的哪个版本。判断的依据是该指针所绑定对象的真实类型。

调用原则:调用函数所使用指针的类型所属类和实际指向的对象所属类共同限制了函数的检索范围,由于不存在从基类向派生类的隐式转换,所以检索范围一定是从实际指向的对象所属类往基类方向向上检索,到使用指针的类型所属类为止。

posted @ 2023-07-11 15:12  CodeMagicianT  阅读(93)  评论(0编辑  收藏  举报