继承的基本知识

概念

假设基于A类,创建了B类,那么称A为B的父类,B为A的子类

子类会继承父类的成员变量及成员函数,但是不能继承构造、析构、运算符重载

假设又基于B创建了C,那么称B为C的直接基类,A为C的间接基类

继承按照字面意思就是继承,而不是包含,当然了在代码中,如果两个类只包含关系,也可以这么写,但是不建议。比如人继承了生物,人包含了生物的属性和方法,同样人包含了脑袋,但是不建议说人继承了脑袋。同样一粒米属于米类,即使一粒米长了翅膀,它也是米的一种,它是由米演变而来的,它继承了米的所有属性及方法,也演变了自己的属性和方法。

语法

class A
{
public:
    int time;
}
class B:public A
{
public:
    int x;
    int y;
}
class C:public B
{
    int hp;
}

这里B继承了A,C继承了B,C包括了A和B的所有成员属性及函数,B只包括了 A的属性及函数

这里如果继承语法里面的public不写,不写就相当于private

protected使用时机

当继承父类时,父类的private成员不能被子类访问,但是父类的private成员在子类的内存中还是存在,只是不能访问,而protected属性和private没有区别,唯一区别是在继承后,它的子类可以访问父类的protected成员

final关键字

当加上关键字后,这个类就不能被继承

public、protected等继承的区别

继承方式为public,则父类中的public成员被继承为public,protected被继承为protected,父类中的private被继承不可访问

继承方式为protected,则父类中的pulic成员被继承为protected,protected被继承为protected,private被继承不可以访问

继承方式为private,父类中的public和protected被继承为private,private成员被继承不可访问

如果我们想要修改子类继承父类的成员权限时,可以用using 父类::成员

class A
{
protected:
	int x;
	int y;
};
class B :public A
{
public:
	using A::x;
};
int main()
{
	B b;
	b.x = 100;
	A a;
	a.x = 200;
}

比如这样,就修改了x在B中的权限,但是这段代码还是不能运行,因为x在A中,还是以proteced的特征存在

构造函数和继承

#include <iostream>
class Object
{
protected:
	char Name[5]{};
public:
	Object()
	{
		std::cout << "Object is created" << std::endl;
	}
};
class seeObject:protected Object
{
public:
	int x;
	seeObject()
	{
		std::cout << "seeObject is created" << std::endl;
	} 
};
int main()
{
	seeObject stone;
	system("pause");
}

这里当实例化seeobject对象 stone时,会同时调用父类的构造函数,因为在子类中继承了父类的成员变量,所以实例化也要实现这个成员变量,从而调用默认构造,构造顺序是父类构造、子类构造,因为在seeobject类的内存中,父类的成员在前面。

#include <iostream>
class Object
{
protected:
	char Name[5]{};
public:
	Object()
	{
		std::cout << "Object is created" << std::endl;
	}
	Object(const Object& obj)
	{
		std::cout << "Object copy is created" << std::endl;
	}
};
class seeObject:protected Object
{
public:
	int x;
	seeObject()
	{
		std::cout << "seeObject is created" << std::endl;
	}
	seeObject(const seeObject& seeobj)
	{
		std::cout << "seeObject copy is created" << std::endl;
	}
};
class creature:protected seeObject
{
protected:
	int hp;
public:
	
	creature()
	{
		x = 3200;
		std::cout << "creature is created" << std::endl;
	}
	creature(const creature& cret)
	{
		std::cout << "creature copy is created" << std::endl;
	}
};
int main()
{
	creature monkey;
	creature monkey2 = monkey;
	system("pause");
}

 这里,子类进行复制构造时,不会调用父类的复制构造函数,子类实例化时都是调用父类的默认构造函数,不会调用其他构造,比如不会调用父类的复制构造,除非显示指定

为什么呢?

当进行复制构造的时候,按理说人类拥有了动物类的所有成员变量,当进行人类的对象复制构造时,那这个时候会调用人类的复制构造函数,动物类的复制构造会不会被调用呢?如果说人类实例化对象也属于动物类的话,那么动物类的复制构造也会被调用,
按照语法规定,不会调用动物类的复制构造,只会调用动物类的构造函数
=========================================================================
为什么会调用动物的普通构造呢?直接一点,直接调用人的复制构造不就好了吗?直接一次性全部打包复制,这是因为人的继承属性,属性必须初始化,而这个属性是属于动物类的,就会默认调用动物的默认构造进行初始化,人不会继承动物的默认构造,但是会调用它
==============================================================================
为什么不调用动物的复制构造呢?就好比,动物有血有肉,人有血有肉,动物的血肉值为100,人的血肉值为200,当复制人的时候,肯定是复制200的血肉值,所以肯定不是调用动物的复制构造,不然血肉值也成了100,只需要把人的继承属性调用动物的普通构造初始化,再加上人的特有属性,两个加起来再调用复制构造复制过去即可。
=========================================================================
为什么不调用人的普通构造呢?因为既然要复制一个人,所以就肯定会调用复制构造,当给人进行普通构造的时候,就好比,初始化一个人的血肉值为10,然后实例化后,将人的血肉值设置为200,那么当复制这个人的时候,肯定不会再调用这个人的普通构造,因为这样又将他设置成了10。所以调用了复制构造肯定不会再调用普通构造
=========================================================================
那么问题来了,按照前面所说,调用了动物的普通构造,将血肉值初识化成了100,只调用人的复制构造,不调用人的普通构造,那么在进行复制的时候,会不会把100也给复制过去呢?不会的,因为在创建这个要复制的对象时,已经给它进行了初始化血肉值为200,就好比要复制一块金子,这块金子早就已经点石成金了,不用担心复制一块石头过去。
=========================================================================

#include <iostream>
class seeObject
{
public:
	int x;
	seeObject()
	{
		std::cout << "seeObject is created" << std::endl;
	}
	seeObject(const seeObject& seeobj)
	{
		std::cout << "seeObject copy is created" << std::endl;
	}
	seeObject(int val) :x{ val }
	{	
	}
};
class creature:protected seeObject
{
protected:
	int hp;
public:
    /using seeObject::seeObject;
	creature():seeObject {100},hp{200}
	{
		x = 3200;
		std::cout << "creature is created" << std::endl;
	}
	creature(const creature& cret):seeObject{cret}
	{
		std::cout << "creature copy is created" << std::endl;
	}
};
int main()
{
	creature monkey;
	creature monkey2 = monkey;
	system("pause");
}

这里,采用成员初始化列表的方式,将100传入seeObject(int val),注意,这里的x=3200,只能写在括号里面,而不能用初始化列表的方式,因为这里还未完成构造

当子类委托构造父类的复制构造函数时,传入的参数是子类类型,也可以,因为子类实例化对象类型也属于父类对象类型,比如人属于动物类,虽然子类多了自己的属性和方法,但它仍然符合父类的定义

==================================

知识扩展*:<1>.通常来说,子类肯定含有父类所有的成员变量和方法函数.所以用父类指针指向子类时,没有问题,因为父类有的,子类都有,不会出现非法访问问题.
<2>.如果用子类指针指向父类的话,一旦访问子类特有的方法函数或者成员变量(基类是没有的),就会出现非法访问;
因为被子类指针指向的由父类创建的对象,根本没有要访问的那些内容,那些是子类特有的,只有用子类初始化对象时才会有
===================================

对于第23行,using seeObject::seeObject;这句代码是继承父类的有参构造函数,使用using继承构造函数是不能继承默认构造和副本构造,其他都可以继承,比如有参构造。继承下来的构造函数不改变它的属性,如果在父类中,它是public,那么继承后,如果把using seeObject::seeObject;这段代码放入creature的private中,它也是public属性。

继承构造时不能选择继承哪个有参构造,而是将所有有参构造全部继承下来

继承和析构

析构的顺序和构造相反,最先析构的是子类,然后才是父类,因为子类对父类有依赖,所以要先析构子类。当把子类中的原有成员销毁时,调用子类的析构,然后销毁继承的成员时,又会调用父类的析构

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值