C++继承的学习笔记

1、在继承中,private类型不能被继承。

公有继承,基类中的public在派生类中还是public类型,protected类型还是protected类型。

保护继承,基类中的public,protected在派生类中均为protected类型。

私有继承,基类中的public,protected均为private类型。

2、当定义一个类对象时,首先从顶层依次调用基类的构造函数,最后调用自身的构造函数。

析构函数的调用顺序与构造函数正好相反,首先调用自身的析构函数,然后依次调用基类的析构函数。

3、子类与父类中函数如果有重名,如果子类中隐藏了父类的方法,那么父类中同名的方法(重载方法)都将被隐藏。

4、在多继承中,当多个基类中有相同的函数名时,需要明确指明调用的是哪一个基类。

5、在多继承中,如果cbird类和cfish类均是canimal的子类,那么当从cbird和cfish中派生出cwaterbird时,将存在两个canimal的拷贝,虚继承将使得子类中只存在一个基类。

6、类型转换是指将某一个类型的对象转换为另一个类型的对象。在应用程序中,对象的类型转换主要是指子类和父类之间的转换。因此这种转换主要有两种形式,向上类型转换和向下类型转换。向上类型转换是指从子类到父类的转换,这种转换是安全的,因为子类具有父类中被外界能够访问的方法。

向下类型转换是从父类到子类的转换,这种类型类型转换是不安全的。因为通常在子类中提供了父类不具有的方法,将父类转换为子类后,试图调用这些实际不存在的方法,必然会出现错误。

向上类型转换是比较安全的,编译器允许直接将子类对象赋值给基类对象。

如下代码:

#include<iostream>
#include<string>
#include<cstring>
using namespace std;
class cemployee
{
protected:
	int m_nid;
    string m_szname;
	string m_szdepart;
public:
	cemployee()
	{
        m_szname="han";

		cout << "employee 构造函数被调用 " << endl;
	}

   virtual void outputname()
	{
		cout << "基函数员工姓名:" << m_szname << endl;
	}
};

class coperator:public cemployee
{
private:
    string m_szpassword;
public:
	coperator()
	{
	    m_szpassword = "123";
		cout << "coperator 构造函数被调用" << endl;
	}


	void outputname()
	{
		cout << "派生类员工姓名:" << m_szname << endl;
	}
};
int main()
{

	coperator * poperator = new coperator();
	cemployee *pemp = poperator;
	pemp->outputname();
//	delete poperator();
	pemp = NULL;

	return 0;
}

cemployee *pemp = poperator;语句直接将子类对象指针直接赋值给基类指针,这是完全合法的。语句pemp->outputname();将调用outputname()方法,如果outputname()是虚函数则调用子类的,否则执行基类的outputname()方法。

向下类型转换。是一种不安全的类型转换,因此编译器不允许直接通过赋值的方式将基类对象赋值给子类的对象。

如下主函数,编译器无法通过。

int main()
{

	cemployee * pemp = new cemployee();
	coperator *poperator = pemp;
	poperator->outputname();
//	delete poperator();
//	pemp = NULL;

	return 0;
}

如果非要实现,可以采用强制转换。改为如下:

int main()
{

	cemployee * pemp = new cemployee();
	coperator *poperator = (coperator*)pemp;
	poperator->outputname();
//	delete poperator();
//	pemp = NULL;

	return 0;
}

上述转换是非常不安全的,如果我们使用poperator 对象调用coperator类特有的方法,例如login()方法。

还有一种可以利用dynamic_cast进行动态转换。利用它可以实现两个比较安全的转换。如果待转换的对象类型与目标类型不相同,则转换将会失败。可以通过转换的结构来判断是否成功。

主函数:

int main()
{

    cemployee * pemp = new coperator();
	coperator *poperator = dynamic_cast<coperator*>(pemp);
	if(poperator != NULL)
	{
		cout << "转换成功" << endl;
	}
	else
		cout << "转换失败" << endl;
	delete pemp;
	poperator = NULL;
        return 0;
}
/*在上述代码中,定义一个父类的指针对象pemp,并用子类的构造函数进行构建。这样,实际上是pemp是一个子类对象。语句“coperator * poperator=<coperator*>(pemp)”将cemployee类型转换为coperator类型对象。如果使用cemployee函数构建,类型转换将会失败。因为源对象pemp构建的类型与目标对象poperator的类型不一致。*/
dynamic_cast有一个缺陷,就是待转换的源对象必须有具有虚拟方法表,即源对象中必须有虚拟方法。可以将析构函数声明为虚析构函数就可以轻松解决这个缺陷。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值