C++入门学习:继承

继承:一个类从另一个类获取成员变量和成员函数的过程

继承的语法:类A 继承 类B

eg:        class A:访问控制符  B

             class Dog : public Animal

类B 就是类A 的基类,类A就是类B的派生类(子类)

继承的一些特性

1、子类拥有父类的所有成员变量和成员函数 
2、子类可以拥有父类没有的方法和属性
3、子类就是一种特殊的父类

4、子类对象可以当作父类对象使用


继承的三种方式:

#include <iostream>
using namespace std;

class Parent
{
public:
	int m_public;
protected:
	int m_protected;
private:
	int m_private;
};

//基类成员在派生类中的权限:在基类中的权限*继承是的权限 = 两者中权限较低者
//							eg: public * private(class Child3 : private Parent) = private
//不管以何种方式继承,基类的私有成员在派生类中是不可使用的

/*
公有继承
1、基类中的public 成员:在派生类中还是 public 属性,在类的内部和外部都可以使用

2、基类中的protected 成员:在派生类中还是 protected 属性,在类的内部可以使用,在类的外部不可以使用

3、基类中的private 成员:在派生类中还是private 属性,在类的内部和外部都不可以使用
*/
class Child1 : public Parent
{
public:
	void use()
	{
		m_public = 1;
		m_protected = 2;
		//m_private = 3;不可用
	}
};

/*
保护继承
1、基类中的public 成员:在派生类中是 protected 属性,在类的内部可以使用,在类的外部不可以使用

2、基类中的protected 成员:在派生类中是 protected 属性,在类的内部可以使用,在类的外部不可以使用

3、基类中的private 成员:在派生类中还是private 属性,在类的内部和外部都不可以使用
*/
class Child2 : protected Parent
{
public:
	void use()
	{
		m_public = 1;
		m_protected = 2;
		//m_private = 3;不可用
	}
};

/*
私有继承
1、基类中的public 成员:在派生类中是private 属性,在类的内部和外部都不可以使用

2、基类中的protected 成员:在派生类还是 private 属性,在类的内部和外部都不可以使用

3、基类中的private 成员:在派生类中是private 属性,在类的内部和外部都不可以使用
*/
class Child3 : private Parent
{
public:
	void use()
	{
		m_public = 1;
		m_protected = 2;
		//m_private = 3;不可用
	}
};

//私有继承后,对Child3的子类来说,祖父类的成员都不可用
class GrandSon : public Child3
{
public:
	void use()
	{
		//m_public = 1;不可用
		//m_protected = 2;不可用
		//m_private = 3;不可用
	}
};

不同的继承方式会影响基类成员在派生类中的访问权限。
 
1) public继承方式
基类中所有 public 成员在派生类中为 public 属性;
基类中所有 protected 成员在派生类中为 protected 属性;
基类中所有 private 成员在派生类中不能使用。
 
2) protected继承方式
基类中的所有 public 成员在派生类中为 protected 属性;
基类中的所有 protected 成员在派生类中为 protected 属性;
基类中的所有 private 成员在派生类中不能使用。
 
3) private继承方式
基类中的所有 public 成员在派生类中均为 private 属性;
基类中的所有 protected 成员在派生类中均为 private 属性;
基类中的所有 private 成员在派生类中不能使用。
 
通过上面的分析可以发现:
1) 基类成员在派生类中的访问权限不得高于继承方式中指定的权限。例如,当继承方式为 protected 时,那么基类成员在派生类中的访问权限最高也为 protected,高于 protected 的会降级为 protected,但低于 protected 不会升级。再如,当继承方式为 public 时,那么基类成员在派生类中的访问权限将保持不变。
 
也就是说,继承方式中的 public、protected、private 是用来指明基类成员在派生类中的最高访问权限的。
 
2) 不管继承方式如何,基类中的 private 成员在派生类中始终不能使用(不能在派生类的成员函数中访问或调用)
 
3) 如果希望基类的成员能够被派生类继承并且毫无障碍地使用,那么这些成员只能声明为 public 或 protected;只有那些不希望在派生类中使用的成员才声明为 private。
 
4) 如果希望基类的成员既不向外暴露(不能通过对象访问),还能在派生类中使用,那么只能声明为 protected。
 
注意,我们这里说的是基类的 private 成员不能在派生类中使用,并没有说基类的 private 成员不能被继承。实际上,基类的 private 成员是能够被继承的,并且(成员变量)会占用派生类对象的内存,它只是在派生类中不可见,导致无法使用罢了。private 成员的这种特性,能够很好的对派生类隐藏基类的实现,以体现面向对象的封装性。


类的对象模型

派生类的内存模型:基类成员放在前面,派生类自己的成员跟在后面进行排列。


类型兼容规则是指在需要基类对象的任何地方,都可以使用公有派生类的对象来替代。通过公有继承,派生类得到了基类中除构造函数、析构函数之外的所有成员。这样,公有派生类实际就具备了基类的所有功能,凡是基类能解决的问题,公有派生类都可以解决。类型兼容规则中所指的替代包括以下情况:

1、派生类成员对象可以代替基类成员对象

2、基类指针可以指向(操作)派生类对象(指针指向派生类对象的内存中与基类内存模型相同的部分)

3、基类的引用可以直接引用派生类对象

4、派生类对象可以直接对基类对象进行初始化和赋值

#include <iostream>

using namespace std;

class Parent
{
public:
	Parent(){}
	Parent(const Parent &p)
	{
		cout << "Parnt 的拷贝构造" << endl;
		a1 = p.a1;
		a2 = p.a2;
	}

	void setP(int a, int b)
	{
		a1 = a;
		a2 = b;
	}

	void showP()
	{
		printf("a1 = %d, a2 = %d\n", a1, a2);
	}
public:
	int a1;
	int a2;
};


class Child:public Parent
{
public:
	void setC(int a, int b)
	{
		b1 = a;
		b2 = b;
	}

	void showC()
	{
		printf("b1 = %d, b2 = %d\n", b1, b2);
	}
public:
	int b1;
	int b2;
};

//1、派生类对象可以代替基类成员对象
void func1()
{
	Parent p1;
	Child c1;
	/*
	p1.setP(1,2);
	p1.showP()
	*/
	c1.setP(1,2);
	c1.showP();
	p1.showP();
}

//2、基类指针可以指向(操作)派生类对象
void show(Parent *p)
{
	p->showP();
}

void func2()
{
	//派生类对象
	Child c1;

	//基类指针
	//指针的操作限制于自身的类型 并不关心指向的是什么东西
	//指针是什么类型解只能做该类型所能做的事情,和指向的对象类型无关
	//p1 是Parent 类型, 所以只能做 Parent能做的事情
	//虽然它指向的是一个派生类对象,但它 还是认为那个对象是一个 Parent类型的对象
	Parent *p1 = &c1;
	p1->setP(3,4);
	p1->showP();

	Child c2;
	c2.setP(5,6);
	Parent p2;
	p2.setP(7,8);

	show(&c2);
	show(&p2);
}

//3、基类的引用可以直接引用派生类对象:引用的本质是常指针
void func3()
{
	Child c1;
	Parent &p1 = c1;//Parent *const p1 = &c1;基于性质2  基类指针可以指向(操作)派生类对象
	p1.setP(1,2);
	c1.showP();
}

//4、派生类对象可以直接对基类对象进行初始化、赋值
void func4()
{
	Child c1;
	c1.setP(1,2);
	c1.setC(3,4);
	//用对象 c1 对 p1 进行初始化
	//Parent (const Parent &p)Parent的拷贝构造函数
	Parent p1 = c1;//调用拷贝构造函数

	Parent p2;
	p2 = c1;//赋值
}

int main()
{
	//func1();
	//func2();
	//func3();
	func4();
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值