C++:继承与派生初探

继承和派生

定义

继承:在定义一个新的类B时,如果该类与某个已有的类A相似(指的是B拥有A的全部特点), 那么就可以把A作为一个基类,而把B作为基类的一个派生类(也称子类)。

  • 派生类是通过对基类进行修改和扩充得到的。在派生类中,可以扩充新的成员变量 和成员函数。
  • 派生类一经定义后,可以独立使用,不依赖于基类。
  • 派生类拥有基类的全部成员函数和成员变 量,不论是private、protected、public 。
  • 在派生类的各个成员函数中,不能访问基类中的private成员。

例:以学生为基类,派生出研究生,大学生,中学生这些子类。

class 派生类名: public 基类名
{
	...
};

派生类对象的内存空间

派生类对象的体积,等于基类对象的体积,再加上派生类对象自己的成员变量的体积。在派生类对象中,包含着基类对象,而且基类对象的存储位置位于派生类对象新增的成员变量之前。

继承关系和复合关系

类之间三种关系:

  • 无关系
  • 继承关系
  • 符合关系

继承:“是”关系

  • 基类 A,B是基类A的派生类。
  • 逻辑上要求:“一个B对象也是一个A对象”。

复合:”有“关系

  • 类C中“有”成员变量k,k是类D的对象,则C和D是复合关系
  • 一般逻辑上要求:“D对象是C对象的固有属性或组成部分”。

例一:”圆“类包含”点“类,这是圆和点就是复合关系

class Circle
{
  	double radius;
  	Point center;
};

例二:人狗关系!最好的写法是互相指向

class Master;

class Dog
{
	Master *pm;
};
class Master
{
  	Dog *dogs[10];
}

基类/派生类同名成员

基类和派生类可以有同名成员函数也可以有同名成员变量。派生类的同名成员会覆盖基类的同名成员,但可以通过域作用符::: 来访问。

一般来说,基类和派生类不定义同名成员变量

protected访问范围说明符

基类的private成员: 可以被下列函数访问:

  • 基类的成员函数
  • 基类的友员函数

基类的public成员: 可以被下列函数访问:

  • 基类的成员函数
  • 基类的友员函数
  • 派生类的成员函数
  • 派生类的友元函数
  • 其他函数

基类的protected成员: 可以被下列函数访问:

  • 基类成员函数
  • 基类友元函数
  • 派生类的成员函数

例:

class  Father 
{
private: 
	int nPrivate;     //私有成员
public:  
	int nPublic;       //公有成员
protected:
	int nProtected;   // 保护成员
}; 

class Son : public Father 
{
	void AccessFather () 
	{
		nPublic = 1; // ok;
		nPrivate = 1;  // wrong
		nProtected = 1; // OK, 访问从基类继承的protected成员
		Son f;
		f.nProtected = 1; //wrong, f不是当前对象
	}
}; 

int main() 
{
	Father f;
	Son s; f.nPublic = 1;   // Ok
	s.nPublic = 1;  // Ok
	f.nProtected = 1;  // error
	f.nPrivate = 1;     // error
	s.nProtected = 1;  //error
	s.nPrivate = 1;   // error
	return 0;
} 

派生类的构造函数

派生类对象包含基类对象

执行派生类构造函数之前, 先执行基类的构造函数

初始化参数列表

构造函数名(形参表):基类名(基类构造函数实参表)
{
	...
}

调用基类构造函数的两种方式

显式:

  • 初始化参数列表
  • derived::derived(arg_derived-list):base(arg_base-list)

隐式:

  • 派生类的构造函数中省略基类构造函数时,派生类的构造函数自动调用基类的默认构造函数

调用顺序

创建派生类的对象 时, 执行派生类的构造函数之前:

  • 调用基类的构造函数:初始化派生类对象中从基类继承的成员
  • 调用成员对象类的构造函数:初始化派生类对象中成员对象

执行完派生类的析构函数后:

  • 调用成员对象类的析构函数
  • 调用基类的析构函数

析构函数的调用顺序与构造函数的调用顺序相反

class Base
{
public:
	int n;
	Base(int i) :n(i)
	{
		cout << "Base " << n << " constructed" << endl;
	}   
	~Base()
	{
		cout << "Base " << n << " destructed" << endl;
	}
};

class Derived :public Base
{
public:
	Derived(int i) :Base(i)
	{
		cout << "Derived constructed" << endl;
	}
	~Derived()
	{
		cout << "Derived destructed" << endl;
	}
};

int main()
{
	Derived Obj(3);
	return 0;
}

// 输出
// Base 3 constructed
// Derived constructed
// Derived destructed
// Base 3 destructed

public继承的赋值兼容规则

class base {};
class derived : public base {};
base b;
derived d;
  • 派生类的对象可以赋值给基类对象:b = d;
  • 派生类对象可以初始化基类引用:base &br = d;
  • 派生类对象的地址可以赋值给基类指针:base *pb = &d;

直接基类和间接基类

在声明派生类时,只需要列出它的直接基类,派生类沿着类的层次自动向上继承它的间接基类

Reference

https://www.coursera.org/learn/cpp-chengxu-sheji/supplement/JYzTL/ke-cheng-slides

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值