面向对象——继承(c++)

目录

一、什么是继承

1.1、继承是什么

1.2、继承的概念与定义

二、继承的设计

由基类派生出派生类的定义一般形式为:

举例:

三、struct(结构体) 与 class(类) 在继承中的区别

四、c++继承的理解

4.1继承父类的派生类成员属性

4.1.1设计代码

4.1.2内存分配

4.1.3能否理解为派生类继承后拥有基类的成员属性?

4.2公有继承、私有继承、保护继承(派生类类成员函数访问)

4.2.1问题分析及代码设计

4.2.2 三种继承(类成员函数访问)

保护继承:

私有继承:

4.2.3总结:

4.3三种继承(继承的对象和成员直接关系)

4.3.1问题分析、代码设计

4.3.2结果分析

​4.3.3总结

4.4三种继承(外部函数和成员函数的区别)

4.4.1问题分析、代码设计

4.4.2结果分析

4.4.3总结

4.5三层继承关系

4.5.1问题分析、代码设计

4.5.2结果分析

 4.5.3总结

4.6继承中的同名隐藏

4.6.1问题分析、代码设计;

4.6.2结果分析

 4.6.3总结

4.7切片问题

4.7.1问题分析、代码设计

4.7.2结果显示

 4.7.3总结

4.7.4 问题一:那如果把上述代码中的参数列表初始化改为如下;会不会改变?

4.7.5思考:基类能否给派生类成员赋值?

4.8拷贝构造、赋值函数是否具有继承性

4.8拷贝构造函数分析

4.8.2代码分析

4.8.3怎样才能调用基类的拷贝构造?


一、什么是继承

1.1、继承是什么

继承(inheritance) 机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础,上进行扩展,增加功能。这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构。体现了由简单到复杂的认识过程。百度百科(继承)

1.2、继承的概念与定义

    通过继承(inheritance)的机制可对类(class) 分层,提供类型/子类型的关系。
        C+ +通过类派生(class derivation)的机制来支持继承。被继承的类称为基类(base class)或超类(superclass),新产生的类为派生类(derived class)或子类(subclass) 。基类和派生类的集合称作类继承层次结构(hierarchy) 。

二、继承的设计

由基类派生出派生类的定义一般形式为:

class 派生类名:访问限定符  基类名1《,访问限定符  基类名2,.....访问限定符  基类名n
{
   private:
      // 成员表1     
      // 派生类增加或替代的私有成员
   public:
      // 成员表2    
      // 派生类增加或替代的公有成员
   protected:
      // 成员表3    
      // 派生类增加或替代的保护成员
};//分号不可少

举例:

class Person {
private:
	char IdPerson[19]; // 编号 
	char Name[20]; //姓名
	  
public:
	Person() { IdPerson[0] = '\0'; Name[0] = '\0'; }
	Person(char* id, char* name) {
		strcpy(IdPerson, id);
		strcpy(Name, name);
	}
	~Person(){};
	void PrintPersonInfo()const {
		cout << "编号" << IdPerson << '\n' << "姓名:" << Name << endl;
	}
};
class Student : public Person
{
private:
	char snum[10];
	float grade;
public:
	Student():Person(){}
	Student(char* id, char* name, char* sn) :Person(id, name) {
		strcpy(snum, sn);
		grade = 0.0;
	}
	~Student(){}
	void PrintStudentInfo()const {
		PrintPersonInfo();
		cout << "学号: " << snum << "\n" << "成绩: " << grade << endl;
	}
	void SetGrade(float ft) {
		grade = ft;
	}
};

总结:派生反映了事物之间的联系,事物的共性与个性之间的关系。派生与独立设计若干相关的类, 前者工作量少,复的部分可以从基类继承来,不需要单独编程。

三、struct(结构体) 与 class(类) 在继承中的区别

  • 1)struct默认属性是公有的,class默认属性是私有的。
  • 2)struct设计一个类型是把它当作一个集合来看待,class设计类型的时候把它当作一个对象来看待。
  • 3)派生类struct在继承的时候缺省访问限定符,就会默认为公有继承,即使继承的是一个class类,也是默认公有继承。如果是派生类class在继承的时候,缺省访问限定符,默认是私有继承。

四、c++继承的理解

4.1继承父类的派生类成员属性

4.1.1设计代码

  • 基类     Object  拥有 整形  value,num ;
  • 派生类  base    拥有 整形  sum ,  fib;

具体实现如下:

class Object {
public:
	int value;
	int num;
public:
	Object(int x = 0, int y = 0) :value(x), num(y) {
		cout << "Create Object :" << this << endl;
	}
};
class Base :public Object {
public:
	int sum;
	int fib;
public:
	Base(int a = 0, int b = 0) :sum(a), fib(b) {
		cout << "Create Base :" << this << endl;
	}
};
int main() {
	Base base1;
}

4.1.2内存分配

面向对象——继承(c++)_第1张图片

4.1.3能否理解为派生类继承后拥有基类的成员属性?

如上图可以把Base派生类分为三部分,如下图:

面向对象——继承(c++)_第2张图片

 所以对于派生类来说有三个成员:隐藏基类对象、sum、flag成员。

4.2公有继承、私有继承、保护继承(派生类类成员函数访问)

4.2.1问题分析及代码设计

探讨各种继承关系之间的派生类对基类成员的访问属性;可以设计如下代码 ;用派生类的fun函数去调用基类的成员;其中  ax是私有成员  ay 保护成员  az是公有成员

类A如下所示:

class A {
private:
	int ax;
protected:
	int ay;
public:
	int az;
public:
	A() { ax = ay = az = 0; }
};

类B如下所示:

class B 
{
private:
	int bx;
protected:
	int by;
public:
	int bz;
public:
	B() { bx = by = bz = 1; }
	void fun() {
		ax = 10; ay = 20; az = 30;
	}
};

4.2.2 三种继承(类成员函数访问)

公有继承:

面向对象——继承(c++)_第3张图片

保护继承:

面向对象——继承(c++)_第4张图片

私有继承:

面向对象——继承(c++)_第5张图片

4.2.3总结:

在继承中;不管那种继承方式私有成员在类内类外都不可访问;

面向对象——继承(c++)_第6张图片

4.3三种继承(继承的对象和成员直接关系)

4.3.1问题分析、代码设计

假设 继承的派生类中含有基类的对象,例如如上派生类代码改为:

class B :public A 
{
private:
	int bx;
	A a;
protected:
	int by;
public:
	int bz;
public:
	B() { bx = by = bz = 1; }
	void fun() {
		//ax = 10; ay = 20; az = 30;
		//a.ax = 15; a.ay = 25; a.az = 35;
	}
};

那么将A a定义在派生类的公有属性、保护属性、私有属性中有什么不同?

4.3.2结果分析

内存图:

面向对象——继承(c++)_第7张图片

 在私有属性中中定义;

面向对象——继承(c++)_第8张图片

 在保护属性中定义:

面向对象——继承(c++)_第9张图片

 在公有属性中:

面向对象——继承(c++)_第10张图片 4.3.3总结

在派生类中声明基类的具有名对象;无论该对象处于什么属性中;只能访问具有名对象的公有属性;

4.4三种继承(外部函数和成员函数的区别)

4.4.1问题分析、代码设计

如果在派生类外的函数中访问派生类的属性会出现什么情况;例如在主函数(main)中给派生类对象赋值会出现什么结果?那种通过不了?为什么? 如果

主函数如图所示:

int main() {
	B b;
	b.bz - 100;
	b.az - 100;
	b.ay - 100;
	b.a.az - 100;
	b.a.ay - 100;
	return 0;
}

4.4.2结果分析

情况一:A a在派生类的公有属性中:派生类公有继承基类

面向对象——继承(c++)_第11张图片

 情况二:派生类私有继承基类

面向对象——继承(c++)_第12张图片

 情况三:将A a定义在保护和私有中A a将都不可访问;

面向对象——继承(c++)_第13张图片

面向对象——继承(c++)_第14张图片  

4.4.3总结

外部函数可以访问类中的公有成员,可以访问公有继承中的公有成员,可以访问公有成员对象中的公有成员。

4.5三层继承关系

4.5.1问题分析、代码设计

三层继承其实和两层继承差不多;理解好其中的关系即可;现在设计三个类;

类A:

class A {
private:     int ax;
protected:   int ay;
public: 	 int az;
public:
	A() { ax = ay = az = 0; }
};

类B:

class B
{
private:     int bx;	
protected:   int by;
public:      int bz;
public: B() { bx = by = bz = 1; }
};

类C:

class C 
{
private:     int cx;
protected:   int cy;
public:      int cz;
};

假设我们改变其中的继承关系会怎样影响类C中的的访问权限?

4.5.2结果分析

情况一:B公有继承A;C公有继承B类;

内存图:

面向对象——继承(c++)_第15张图片

 fun函数中都能访问;但是A类和B类的私有成员不能访问;

情况二:将B类公有继承A类改为私有继承A类会怎样;

面向对象——继承(c++)_第16张图片

情况三: 将B类私有继承A类改为保护继承A类会怎样;

面向对象——继承(c++)_第17张图片

 4.5.3总结

在多层继承中;派生类能否访问基类的对象成员;在于基类继承的基类成员是什么属性;如果基类继承私有继承;那么在基类的成员属性就为基类的私有成员;而私有成员被继承下来是不可访问的;

4.6继承中的同名隐藏

4.6.1问题分析、代码设计;

看如下代码的运行;思考运行结果ax=100是赋值给基类A还是派生类B;

class A
{
protected:
	int ax;
public:
	A() :ax(0) {}
};
class B :public A
{
private:
	int ax;
public:
	B():ax(10){}
	void fun() {
		ax = 100;
	}
};
int main() {
	B b;
	b.fun();
}

内存图:

面向对象——继承(c++)_第18张图片

 那如果调用fun()函数了;我们都知道;会首先构建基类对象对象,那赋值是不是也先给基类对象赋值?

4.6.2结果分析

面向对象——继承(c++)_第19张图片

 4.6.3总结

如果派生类与基类有相同的函数名字或者对象名字;派生类会访问自己的对象(就近原则);或者理解为编译期时候派生类对象隐藏了基类同名对象;所谓同名隐藏;

那怎么可以访问了?回答:假设类的作用域;

面向对象——继承(c++)_第20张图片

4.7切片问题

4.7.1问题分析、代码设计

在继承中,派生类对象是否可以给基类对象赋值?

class Object
{
private:
	int value;
public:
	Object(int x = 10) :value(x) {}
	~Object() {}
};
class Base :public Object {
private:
	int num;
public:
	Base(int x = 0) :num(x), Object(x + 10) {}
	~Base() {};
};

如果main函数作如下处理会不会改变基类的对象值?

	Object obja(100);
	Base s1(10);

4.7.2结果显示

面向对象——继承(c++)_第21张图片

 4.7.3总结

派生类在初始化时,通过参数列表改变基类的值,会发生切片现象;但是必须在公有继承之下;

4.7.4 问题一:那如果把上述代码中的参数列表初始化改为如下;会不会改变?

class Base :public Object {
private:
	int num;
public:
	Base(int x = 0) :num(x)
	{
		Object(x + 10);
	}
	~Base() {};
};

面向对象——继承(c++)_第22张图片

4.7.5思考:基类能否给派生类成员赋值?

4.8拷贝构造、赋值函数是否具有继承性

4.8拷贝构造函数分析

代码如下;是想用base能base2赋值;能不能调动基类的拷贝构造?

class Object
{
private:
	int value;
public:
	Object(int x = 10) :value(x) { cout << "Create Object :" << this << endl; }
	~Object() { cout << "Destroy Object :" << this << endl; }
	Object(const Object& obj) :value(obj.value) {
		cout << "Copy Create Object :" << this << endl;
	}
};
class Base :public Object {
private:
	int num;
public:
	Base(int x = 0) :num(x), Object(x + 10) { cout << "Create Base:" << this << endl; }
	~Base() { cout << "Destroy Base: " << this << endl; }
	Base(const Base& base) :num(base.num) {
		cout << "Copy Creater Base :" << this << endl;
	}
};
int main() {
	Base base(10);
	Base bas2(base);
	return 0;
}

4.8.2代码分析

面向对象——继承(c++)_第23张图片

 面向对象——继承(c++)_第24张图片

 所以并不会去调用基类的拷贝构造函数;也就是说拷贝构造函数不具有继承性;

4.8.3怎样才能调用基类的拷贝构造?

面向对象——继承(c++)_第25张图片

原因是赋值兼容规则;上文有讲述; 4.7


 

你可能感兴趣的:(C/C++,c++,继承,赋值兼容,c++继承,面向对象)