C++>继承,继承方式及其比较,子类和父类对象指针,派生类的默认成员函数,虚继承,继承与友元,继承与静态成员

继承

继承的概念与定义

概念:

继承是指一个子类(或称为派生类)继承父类(或称为基类)的特征(属性和操作)。继承是面向对象程序设计时实现代码复用的重要手段,它允许在原有的类的基础上进行扩展,增加功能,这样新产生的类称为子类。

定义:

class 子类名:继承方式 父类名;

class Student:public Person		//Person是基类,Student是派生类,public是继承方式
	{
	public:
		int _stuid;		//学号
		int _major;		//专业
	};

继承的作用

1>使软件系统具有开放性;
2>更好地进行抽象与分类;
3>增强代码的重用率;
4>提高可维护性。

继承方式

1>public公有继承

1.基类public和protected成员的访问属性在派生类中不变,并且基类的private成员不可访问。
2.派生类中的成员函数可以直接访问基类中的public和protected成员,但基类的private成员不可被访问。
3.派生类的对象只能访问基类的public成员。

2>protected保护继承

1.基类的public和protected成员都以protected成员的身份出现在派生类中,并且基类的private成员不可访问。
2.派生类中的成员函数可以直接访问基类中的public和protected成员,但基类的private成员不可被访问。
3.派生类的对象不能访问基类中的任何成员。

3>private私有继承

1.基类的public和protected成员都以private成员的身份出现在派生类中,并且基类的private成员不可访问。
2.派生类中的成员函数可以直接访问基类中的public和protected成员,但基类的private成员不可被访问。
3.派生类的对象不能访问基类中的任何成员。

总结:

1.基类的private成员不论以何种方式继承在派生类中都是不可被访问的。
2.保护继承和私有继承将改变基类中public和protected成员在派生类中的身份为protected和private,使得这两种继承方式下派生类的对象失去了访问基类的public成员的权限,而对派生类中的成员函数没有什么影响。
3.使用class关键字时默认的继承方式是private,使用struct关键字时默认的继承方式是public。

父类成员的访问控制

父类的public成员允许本类,子类和类外部(非本类和子类)的访问;
父类的protected成员允许本类和子类的访问;
父类的private成员只允许本类访问。

基类和派生类的对象赋值转换

1>派生类的对象可以赋值给基类的对象/基类的指针/基类的引用。这里有个形象的说法叫切片,指将派生类中父类的那部分分切下来赋值给基类。
2>基类对象不能赋值给派生类对象。
3>基类的指针可以通过强制类型转换赋值给派生类的指针。但必须是基类的指针指向派生类的对象才是安全的,
基类如果是多态类型可以使用RTTI的dynamic_cast来识别后进行安全转换。

赋值兼容规则

1>派生类对象可以给基类对象赋值,这种情况下派生类对象将从基类继承的成员的值赋值给一个基类对象;但是不允许将一个基类的对象赋值给一个派生类。
2>可以将派生类对象的地址赋给基类指针,使基类指针指向派生类对象,通过基类指针引用成员时只可以引用派生类从基类继承而来的成员,而不允许引用派生类的新成员。
3>引用与指针相同。

继承中的作用域

1>在继承体系中基类和子类都有独立的作用域。
2>子类和父类中有同名成员,子类成员将屏蔽父类成员成员的直接访问,这种情况叫隐藏,也叫直接访问。(在子类成员函数中,可以使用 基类::基类成员 进行显示访问)。
3>若是成员函数的隐藏,只要是函数名相同(参数不一样或者返回类型不一样)就构成隐藏。

子类和父类对象的指针

1>在public继承方式下父类的对象指针可以指向子类对象,子类的对象指针不可以指向父类对象,并且,将父类的对象指针指向子类对象后,该指针无法使用子类中扩展的成员。
2>父类指针无法直接调用子类的新函数,需要转换为子类指针后才能调用。转换方式人如下:
1.强制转换方式,不安全,因为转换的时候无法得知是否转换成功,可能会导致程序崩溃。
2.动态转换方式,dynamic_cast是在运行时去做转换而非编译时,所以它可以给出是否转换成功的信息。如果转换不成功则返回NULL。所以可以判断转换结果是否为NULL来决定是否能使用该指针不会导致程序崩溃。

派生类的默认成员函数

1>初始化构造函数

派生类的构造函数必须调用基类调用基类的构造函数初始化基类的那一部分成员。如果基类没有默认的构造函数,则必须在派生类的构造函数的初始化列表阶段显示调用。父类的构造函数先运行,然后再运行子类的构造函数。也可以说子类对象是在父类对象的基础上扩展而成的。我们可以使用下面的格式将子类构造函数的参数传递给父类构造函数的的参数:
子类名::构造函数(参数表):父类名(参数列表)

Cat(char_name[30],float_weight,int_age):Animal(_name,_weight,_age)
{
	cout<<"Cat(char_name[30],float _weight,int _age):Animal(_name,_weight,_age)is called"<<endl;
}
2>析构函数

派生类的析构函数会在被调用完成后自动调用基类的析构函数进行基类程丽媛的清理。析构函数的运行顺序和构造函数的巡行顺序相反。

3>拷贝构造函数

派生类的拷贝构造函数必须调用基类的拷贝构造函数完成基类的拷贝初始化。

4>运算符重载

派生类的operator=必须调用基类的operator=完成基类的重载。

继承与友元

友元关系不能继承,也就是说基类友元不能访问子类私有和保护成员。

继承与静态成员

基类定义了static静态成员,则整个体系只能有一个这样的成员,无论派生出多少个子类,都只有一个static成员实例。

继承的分类

单继承:

一个子类只有一个直接父类时称这个继承关系为单继承。

多继承:

一个子类有多个直接父类时称这个继承关系为多继承。多继承继承列表父类的先后决定了继承顺序。
class 子类名:继承方式1 父类名1,继承方式2 父类名2;

class Frog:public TerrestrialAnimal,public AquaticAnimal	
	{};//Frog(青蛙)既是TerrestrialAnimal(陆生脊椎动物)又是AquaticAnimal(水生脊椎动物)

菱形继承(父类分解)

菱形继承是多继承的一种特殊情况。菱形继承有数据冗余和二义性的问题。虚继承可以解决数据二义性的问题。如上TerrestrialAnimal与AquaticAnimal都继承于Animal父类,那它们与Frog构成菱形继承。

虚继承

1>定义:

虚继承是在声明继承关系时,在继承的类前面加上virtual关键字,这时被继承的类称为虚基类。

class TerrestrialAnimal:virtual public Animal	//TerrestrialAnimal虚继承Animal
2>特点:

1.普通虚拟继承比普通单继承多4个字节,用于存放虚基表指针,指向虚基表,虚基表中存放这偏移量,通过偏移量可以找到Animal的成员。
2.虚继承中子类部分在上,基类部分在下。存放顺序为TerrestrialAnimal虚基表指针>TerrestrialAnimal成员>AquaticAnimal虚基表指针>AquaticAnimal>Frog成员>Animal成员。其中AquaticAnimal虚基表中的指针偏移量要比TerrestrialAnimal虚基表中的指针偏移量大sizeof(TerrestrialAnimal虚基表指针+TerrestrialAnimal成员)。
C++>继承,继承方式及其比较,子类和父类对象指针,派生类的默认成员函数,虚继承,继承与友元,继承与静态成员_第1张图片

不能被继承的类

1>C++98中构造函数私有化,派生类调不到基类的构造函数,则无法继承。
2>C++11给出了新的关键字final禁止继承

class Mosquito final  //希望蚊子灭绝
{};

你可能感兴趣的:(#,C++)