目录
一、什么是继承
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怎样才能调用基类的拷贝构造?
继承(inheritance) 机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础,上进行扩展,增加功能。这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构。体现了由简单到复杂的认识过程。百度百科(继承)
通过继承(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;
}
};
总结:派生反映了事物之间的联系,事物的共性与个性之间的关系。派生与独立设计若干相关的类, 前者工作量少,复的部分可以从基类继承来,不需要单独编程。
具体实现如下:
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;
}
如上图可以把Base派生类分为三部分,如下图:
所以对于派生类来说有三个成员:隐藏基类对象、sum、flag成员。
探讨各种继承关系之间的派生类对基类成员的访问属性;可以设计如下代码 ;用派生类的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;
}
};
公有继承:
在继承中;不管那种继承方式私有成员在类内类外都不可访问;
假设 继承的派生类中含有基类的对象,例如如上派生类代码改为:
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;
}
};
内存图:
在私有属性中中定义;
在保护属性中定义:
在公有属性中:
在派生类中声明基类的具有名对象;无论该对象处于什么属性中;只能访问具有名对象的公有属性;
如果在派生类外的函数中访问派生类的属性会出现什么情况;例如在主函数(main)中给派生类对象赋值会出现什么结果?那种通过不了?为什么? 如果
主函数如图所示:
int main() {
B b;
b.bz - 100;
b.az - 100;
b.ay - 100;
b.a.az - 100;
b.a.ay - 100;
return 0;
}
情况一:A a在派生类的公有属性中:派生类公有继承基类
情况二:派生类私有继承基类
情况三:将A a定义在保护和私有中A a将都不可访问;
外部函数可以访问类中的公有成员,可以访问公有继承中的公有成员,可以访问公有成员对象中的公有成员。
三层继承其实和两层继承差不多;理解好其中的关系即可;现在设计三个类;
类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中的的访问权限?
情况一:B公有继承A;C公有继承B类;
内存图:
fun函数中都能访问;但是A类和B类的私有成员不能访问;
情况二:将B类公有继承A类改为私有继承A类会怎样;
情况三: 将B类私有继承A类改为保护继承A类会怎样;
在多层继承中;派生类能否访问基类的对象成员;在于基类继承的基类成员是什么属性;如果基类继承私有继承;那么在基类的成员属性就为基类的私有成员;而私有成员被继承下来是不可访问的;
看如下代码的运行;思考运行结果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();
}
内存图:
那如果调用fun()函数了;我们都知道;会首先构建基类对象对象,那赋值是不是也先给基类对象赋值?
如果派生类与基类有相同的函数名字或者对象名字;派生类会访问自己的对象(就近原则);或者理解为编译期时候派生类对象隐藏了基类同名对象;所谓同名隐藏;
那怎么可以访问了?回答:假设类的作用域;
在继承中,派生类对象是否可以给基类对象赋值?
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);
派生类在初始化时,通过参数列表改变基类的值,会发生切片现象;但是必须在公有继承之下;
class Base :public Object {
private:
int num;
public:
Base(int x = 0) :num(x)
{
Object(x + 10);
}
~Base() {};
};
代码如下;是想用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.7