(C++对象模型):静动态类型、绑定,坑点,多态体现深谈

目录

静动态类型、绑定,坑点,多态体现深谈

静态类型和动态类型

静态绑定和动态绑定

继承的非虚函数坑

虚函数的动态绑定

重新定义虚函数的缺省参数坑

c++ 中的多态性的体现

静动态类型、绑定,坑点,多态体现深谈

静态类型和动态类型

  • 静态类型:对象定义时的类型编译期间就确定好
  • 动态类型:对象目前所指向的类型运行的时候才决定的类型
    • 一般只有指针或者引用才有动态类型的说法,而且一般都是指父类的指针或者引用
class Base
{
public:
	
};
class Derive :public Base
{
public:
	
};
class Derive2 :public Base
{
public:

};


int main()
{
Base base; //base的静态类型是Base,没有动态类型,因为不是指针不是引用
Derive derive; //derive的静态类型是Derive,没有动态类型,因为不是指针不是引用
Base *pbase; //pbase的静态类型依旧是Base *  ,至少目前没有动态类型,因为它没有指向任何对象
Base *pbase2 = new Derive(); //pbase2的静态类型依旧是Base * ,动态类型是Derive 
Base *pbase3 = new Derive2(); //pbase3的静态类型依旧是Base *,动态类型是Derive2 

return 0;
}
  • 动态类型在执行过程中可以改变:比如
//Base *pbase; pbase的静态类型依旧是Base *  ,至少目前没有动态类型,因为它没有指向任何对象
pbase = pbase2; //pbase的动态类型Derive
pbase = pbase3; //pbase的动态类型改变为Derive2

静态绑定和动态绑定

  • 静态绑定:绑定的是静态类型,所对应的函数或者属性依赖于对象的静态类型,发生在编译期
  • 动态绑定:绑定的是动态类型,所对应的函数或者属性依赖于对象的动态类型,发生在运行期
    • 普通成员函数是静态绑定,而虚函数是动态绑定
    • 缺省参数一般是静态绑定
       

继承的非虚函数坑

class Base
{
public:
	void myfunc() //普通成员函数
	{
		cout << "Base::myfunc()" << endl;
	}
	
};
class Derive :public Base
{
public:
	void myfunc() //普通成员函数
	{
		cout << "Derive ::myfunc()" << endl;
	}
	
};

int main()
{
	Derive derive;
	Derive *pderive = &derive;
	pderive->myfunc(); //Derive::myfunc()

	Base *pbase = &derive;
	pbase->myfunc(); //Base::myfunc()

    return 0;
}
  • 普通成员函数是静态绑定,换句话说,myfunc() 是普通成员函数,这里到底调用父类的myfunc还是子类的myfunc取决于调用者的静态类型。
  • 因为这里pbase的静态类型是Base,送一调用的是Base里的myfunc();pderive的静态类型是Derive *,所以调用的是Derive的myfunc();
  • 结论不应该在子类中重新定义一个继承来的非虚函数。

虚函数的动态绑定

  • 执行哪个类型的函数,先确定此时指针或引用的动态类型是什么。
class Base
{
public:
	void myfunc() //普通成员函数
	{
		cout << "Base::myfunc()" << endl;
	}
	}
	virtual void myvirfunc()
	{
		cout << "Base::myvirfunc()" << << endl;
	}
};
	
};
class Derive :public Base
{
public:
	void myfunc() //普通成员函数
	{
		cout << "Derive ::myfunc()" << endl;
	}
	virtual void myvirfunc()
	{
		cout << "Derive ::myvirfunc()" << << endl;
	}
	
};

int main()
{
	Derive derive;
	Derive *pderive = &derive;
	pderive->myfunc(); //Derive::myfunc()

	Base *pbase = &derive;
	pbase->myfunc(); //Base::myfunc()

	Base base;
	pderive->myvirfunc(); //执行Derive的myvirfunc(); ---  Derive::myvirfunc()
	pbase->myvirfunc(); //pbase动态类型是Derive,而虚函数是动态绑定,参照是它的动态类型;---  Derive::myvirfunc()	                    
	           
	pbase = &base;  
	pbase->myvirfunc(); //----Base::myvirfunc();

    return 0;
}
  • 虚函数是动态绑定,换句话说,myvirfunc()是虚函数,这里到底执行哪个myvivfunc()取决于调用者的动态类型
    • pderive的动态类型是Derive,所以调用的是Derive的myvirfunc()
    • 这里pbase的动态类型分别Derive,Base,所以调用的也分别是Derive和Base的myvirfunc()

重新定义虚函数的缺省参数坑

class Base
{
public:
	void myfunc() //普通成员函数
	{
		cout << "Base::myfunc()" << endl;
	}
	virtual void myvirfunc(int value = 1)
	{
		cout << "Base::myvirfunc(),value = " << value << endl;
	}
};
class Derive :public Base
{
public:
	void myfunc() //普通成员函数
	{
		cout << "Derive::myfunc()" << endl;
	}
	virtual void myvirfunc(int value = 2)
	{
		cout << "Derive::myvirfunc(),value = " << value << endl;
	}
};

int main()
{
	Derive derive;
	Derive *pderive = &derive;
	pderive->myfunc(); //Derive::myfunc()

	Base *pbase = &derive;
	pbase->myfunc(); //Base::myfunc()

	Base base;
	pderive->myvirfunc(); //执行Derive的myvirfunc(); ---  Derive::myvirfunc()
	pbase->myvirfunc(); //pbase动态类型是Derive,而虚函数是动态绑定,参照是它的动态类型;---  Derive::myvirfunc()	 

	                       //缺省value参数打印出来的是1:Derive::myvirfunc(),value = 1
	                       //这就始于函数参数缺省值的静态绑定,所以缺省参数绑定到了父类函数的缺省参数上去了                   
	           
	pbase = &base;  
	pbase->myvirfunc(); //----Base::myvirfunc();

    return 0;
}
  • 调用子类虚函数,用的是父类的虚函数的缺省值,因为缺省值一般是静态绑定,,所以缺省参数绑定到了父类函数的缺省参数上去了                   

  • 由于函数参数缺省值的静态绑定,不要重新定义虚函数的缺省参数的值。

c++ 中的多态性的体现

  • 多态性 这个概念,分两方面谈:
    • 从代码实现上
    • 从表现形式上
  • 有一个观点是肯定的:多态,必须是存在虚函数,没有虚函数,绝不可能存在多态,有虚函数并且通过虚函数表调用虚函数

从代码实现上

  • 当调用一个虚函数时,走的是不是通过查询虚函数表来找到虚函数入口地址
  • 然后去执行虚函数,如果走的是这个途径,那就是多态,如果不走这个途径,它就不是多态
class A
{
public:
	virtual void myvirfunc() {}
};

int main(){
	A *pa = new A();
	pa->myvirfunc(); //是不是多态,是多态

	A a;
	a.myvirfunc(); //这个就不是多态

	A *pa1 = &a;
	pa1->myvirfunc(); //这个也是多态

    return 0;
}
  • 反汇编,查看是否通过虚函数表调用虚函数

  • 虚函数是有地址的,编译时就确定了。

从表现形式上(通过代码来体现)

  1. 有继承关系,有父类有子类,父类中必须有虚函数(这意味着子类中一定有虚函数),子类重写父类的虚函数;
  2. 父类指针或者引用指向子类对象
  3. 当以父类指针或者 引用调用子类中重写了的虚函数时,就能看出来多态的表现了,因为调用的是子类的虚函数。
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值