【技术类】c++多态

多态分为静多态和动多态,静多态包括模板,函数重载,是在编译时期就已经确定的,动多态是在运行时确定。
体现在汇编上的差异(静多态 call 0x地址)(动多态 call eax)
class Abstract
{
public:
	virtual void f() = 0{ cout << "over" << endl; };
	virtual void g() = 0;
};

class Dev:public Abstract
{
public:
	void f(){}
	void g(){}
	//virtual void r(){ cout << "Dev::r" << endl; }
};
/*
	1.派生类会继承基类的虚表。
	2.派生类构造时来确定对象中的虚表指针该指向哪
	3.虚函数表在编译时期就有了,并且放在rodata中
	4.纯虚函数可以有函数体,但没啥意义。
*/
//class Rt :public Dev
//{
//public:
//	void r(){}
//	void r(int x){}
//};

int main()
{
	Dev v;
	v.f();
	//Rt t;
	//t.r(1);

	//Abstract as;
	//Dev de;

	//cout << sizeof(de) << endl;
	
	return 0;
}
#if 0
//如果基类中该函数有默认参,发生多态时默认使用该默认参。

class Base
{
public:
	static void f(){ cout << "Base f" << endl; }
	static int c;

	virtual void tr(int x = 10){ cout << x << endl; }
};
int Base::c = 10;

class Dev:public Base
{
public:
	void g(int x)
	{
		//Base::f();
		c = x;
	}
	void p(){ cout << c << endl; }
	
	void tr(int x = 11){ cout << "Dev::"<<x << endl; }
	
};

int main()
{
	Dev de;
	de.g(11);

	Dev de1;
	de1.g(12);

	//de.p();
	//de1.p();

	Base &p = de;
	p.Base::tr();
	
	//Base *p1 = &de;

	//p1->tr();
	//cout << sizeof(de) << endl;

	//fun2(20);
	return 0;
	
#endif
}
#if 0
class Base
{
public:
	Base(){};
	/*
		virtual Base();
		如果使用了virtual那么构造函数就要通过vptr找到vtable,
		但是vptr是在构造函数中完成的,那么vtable就无法找到。
		因此,不可以有虚构造函数。
	*/
	
	virtual ~Base(){ cout << "~Base" << endl; }
	/*
		当一个类作为基类时,尽可能的把它的析构写为virtual,
		防止X类继承了该类的,那么X类中动态申请的内存就不能
		得到释放,发生内存泄露。

		如果确定不作为基类,就别写了,写了也多占内存。
	*/
private:
	int b;
};

class Dev:public Base
{
public:
	Dev(){};
	~Dev(){ cout << "~Dev" << endl; };
private:
	int d;
};

int main()
{
	//Dev v;
	Base *p = new Dev();
	delete p;
	/*
		动态绑定,分析对象类型,并调用它的析构函数。
		因此,会先调用Dev析构。由于继承关系,再调用
		Base的析构。
	*/
	return 0;
}
#endif
#if 0
//哪些函数不能实现为虚函数?
1.普通函数
/*
	virtual void fun1){};
	virtual关键字不允许使用在类外,因此普通函数不能实现为虚函数。
*/

2.内联函数
/*
	inline virtual void fun();
	内联函数在编译时期展开,与虚函数通过函数实现多态相背。
	尴尬的是上面这样的定义,本应当是不对的。但编译通过了,
	并且sizeof(Base)=4。 也就是编译器对我建议的显式line完
	全不理视。(内联只是建议,决定权在编译器手里)
*/

3.静态函数
/*	
	virtual static void fun();
	首先静态函数是可以被继承的,但它在编译时期就被确定了属
	于哪个类是确定的,不会再更改。
	因此,静态函数是不可以被virtual修饰进行重写,想发生多态
	是不可能了。
*/

4.友元函数
/*	
	virtual friend void fun();
	编译失败,友元函数不能被继承,非继承特性的函数
	不允许被virtual修饰。
*/
};
#if 0
/*
	理解分析虚基类
*/
class Base0{
public:
	Base0(int var = 1):var0(var){}
	int var0;
};

class Base1 :virtual public Base0{
public:
	Base1():Base0(10){}
	int var1;
};

class Base2 :virtual public Base0{
public:
	Base2():Base0(20){}
	int var2;
};

class Derived :public Base1, public Base2{
public:
	Derived(){}
};

int main(){
	Derived d;					   

	cout << sizeof(d) << endl;		//20
	/*
		内存布局
		*******************
		*	***************		
		*	*Base1:vbptr **
		*	*	   var1  **
		*******************
		*	*Base2:vbptr **
		*	*	   var2	 **
		*	***************
		*	var0		 **
		*******************
		由于虚继承原因,内存布局产生了变动,为了每一个类能正确指到虚基类的数据
		因此为每一个直接或间接基类产生一个vbptr,可以指向例如此例中的var0

		结论:1.最远建立对象的构造中,虚基类的成员是直接通过虚基类的构造函数构造的,
				尽管途中有其他对虚基类的构造有所指定,但不执行。

			  2.虚基类的构造先于任何一个非虚基类

			  3.vbptr表项
				vbptr[0]	当前最近作用域的偏移 - vbptr的偏移(一般为0)
				vbptr[1]	虚继类数据的起始偏移 - vbptr的偏移(可以正确指到数据)
				vbptr[2]	还有数据的话就以此类推

			  4.vfptr表项
			  **************************************************
			  * RTTL(run time type information)运行时类型信息*
			  **************************************************
			  * 虚函数指针的偏移	(-8)					   *
			  **************************************************
	vfptr-->  * 虚函数的入口地址(第一个虚函数入口/地址)	   *									  *
			  **************************************************
			  *	还有虚函数的依次向下											   *
			  **************************************************
			  虚表的写入时机 构造函数的执行之前
			 
		class Derived :virtual public Base
		此时继承关系为虚拟基类继承,那么在使用是编译器会为Derived类
		隐式加上一个vbptr。因为Derived有可能和其他类有共同基类,避免
		重复,内存的浪费。用vbptr来指向他们共同的正确数据。
	*/
	return 0;
}
#endif
#if 0
/*
	重载 隐藏 覆盖(复写)
*/

class Base
{
public:
	void fun(){ cout << "Base::fun" << endl; }
	virtual void fun(int i){}
};

class Dev : public Base
{
public:
	void* fun(){ cout << "Dev::fun" << endl; return NULL; }	
	void fun(int i){}
};

int main()
{
	Dev v;
	v.fun()

	return 0;
}
#endif
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值