学习资源来源于中国慕课
继承
定义: 在已经定义了一个类A之后,再定义一个类B,并且类B有类A的所有成员(包括成员函数和成员变量),那么类A就叫做基类,类B叫做派生类,也称为子类。简单说来,就相当于类B是在类A上的扩张定义。但两者时独立的关系,可以独立使用。
示例
概括所有事物的共同特点,写一个基类。然后为 每种事物写一个类,都从基类派生而来。而派生类的写法是:类名: public 基类名如class B:public A
派生类对象的内存空间
派生类对象的体积,等于基类对象的体积,再加上派 生类对象自己的成员变量的体积。在派生类对象中,包含着基类对象,而且基类对象的存储位置位于派生类对象新增的成员变量之前。
示例2
#include<iostream>
#include<iomanip>
using namespace std;
class student {
private:
string name;
public:
student() { name ="casv"; }
void setname(const string& _name) { name = _name; }
string GetName() { return name; }
void PrintInfo() {
cout <<"Name:"<< GetName() << endl;
}
};
class UnderGrateStudent :public student {
private:
string department = "vsdv";
public:
void QualifiedForBaoYan() { cout << "有保研资格" << endl; }
void PrintInfo() {
student::PrintInfo();//第一个类的函数
cout << "department:"<< department << endl;
QualifiedForBaoYan();
}
};
class UnderStudent :public student {
private:
int department = 123;
char MentorName[20] = "scs";
public:
void PrintInfo() {
student::PrintInfo();//第一个类的函数
cout << "department:" << department << " MentorName:" << MentorName << endl;
}
};
int main()
{
student s1;
s1.setname("aa");
s1.PrintInfo();
UnderGrateStudent s2;
s2.setname("bb");
s2.PrintInfo();
UnderStudent s3;
s3.setname("cc");
s3.PrintInfo();
return 0;
}
执行效果
继承关系和复合关系
类之间的两种关系
如几何形体程序中,需要写“点”类,也需要写“圆”类,两 者的关系就是复合关系 ---- 每一个“圆”对象里都包含 (有)一个“点”对象,这个“点”对象就是圆心
class CCircle;
class CPoint {
double x,y;
friend class CCircle;//便于Ccirle类操作其圆心
};
class CCircle {
double r;
CPoint center;
};
复合关系讨论
如果一个很优秀的人在北京有十套房子,那么如何写类呢?(房子与人的关系)
- 此定义是循环定义,不正确
class human;
class house {//一套房子的主人
human a;
};
class human {//一个人有十套房子
house home[10];
};
- 为“房子”类设一个“人”类的成员对象; 为“人”类设一个“房子”类的对象指针数组。但是修改10个房子的主任,需要修改十次,太重复了。
class human;
class house {
human a;
};
class human {
house *home[10];
};
- 为“人”类设一个“房子”类的成员对象数组; 为“房子”类设一个“房子”类的对象指针.如此,每一个房子都指向同一个人。
class human;
class house {
human *a;//指向同一个人
};
class human {
house home[10];
};
- 最好的方式是
class human;
class house {
human *a;
};
class human {
house *home[10];
};
派生类覆盖基类成员
派生类可以定义一个和基类成员同名的成员,这叫 覆盖。在派生类中访问这类成员时,缺省的情况是 访问派生类中定义的成员。要在派生类中访问由基 类定义的同名成员时,要使用作用域符号::。
一般来说,基类和派生类不定义同名成员变量。
类的保护成员
三种类型总结
派生类的构造函数
- 在创建派生类的对象时,需要调用基类的构造函数:初始化派 生类对象中从基类继承的成员。在执行一个派生类的构造函数 之前,总是先执行基类的构造函数。
- 调用基类构造函数的两种方式
– 显式方式:在派生类的构造函数中,为基类的构造函数提供参数
– 隐式方式:在派生类的构造函数中,省略基类构造函数时, 派生类的构造函数则自动调用基类的默认构造函数. - 派生类的析构函数被执行时,执行完派生类的析构函数后,自 动调用基类的析构函数。因为基类的内部, 有一些是派生类不了解的. 为了方便,为了安全,为了管理. 所以派生类的对象销毁的时候, 继承机制会分级调用各级的析构函数。
#include<iostream>
#include<iomanip>
using namespace std;
class A {
private:
int leg;
int color;
public:
int type;
A(int _leg, int _color);
void print() {
cout <<"leg:"<< leg << " color:" << color << " " << endl;
}
};
class B :public A {
private:
int wing;
public:
B(int _leg, int _color, int _wing);
void print() {
A::print();
cout << "wing:" << wing << " type:" << type << endl;
}
};
A::A(int _leg, int _color) {
leg = _leg;
color = _color;
}
B::B(int _leg, int _color, int _wing) :A(_leg, _color) {
wing = _wing;
}
int main()
{
B a(1, 2, 3);
a.type = 1;
a.print();
return 0;
}
执行效果
函数执行顺序判断:在执行一个派生类的构造函数 之前,总是先执行基类的构造函数。派生类的析构函数被执行时,执行完派生类的析构函数后,自 动调用基类的析构函数。
public继承的赋值兼容规则
注意:如果派生方式是 private或protected,则上述三条不可行。
基类与派生类的指针强制转换
直接基类和间接基类
#include<iostream>
#include<iomanip>
using namespace std;
#include <iostream> using namespace std;
class Base {
public:
int n;
Base(int i) :n(i){}
~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;
}
};
class MoreDerived :public Derived {
public:
MoreDerived() :Derived(4) { cout << "More Derived constructed" << endl;}
~MoreDerived() { cout << "More Derived destructed" << endl; }
};
int main() {
MoreDerived Obj;
return 0;
}
执行效果