类的继承与派生——第七章总结
继承与派生———第七章总结作业
一、继承和派生的相关基本概念
- [类的继承]:新的类从已有的类得到已有的属性的过程
- [类的派生]:从已有类产生新类的过程
- 原有的类称为[基类]或[父类],新的类称为[派生类]或[子类]
- [多继承]:一个类可以有多个继承,反之只有一个继承的称为[单继承]
//单继承
class 派生类名:继承方式 基类名{
成员声明;
}
//多继承
class 派生类名:继承方式1 基类名,继承方式2 基类名...{
成员声明;
}
- 在类族中,直接参与派生出某类的基类称为[直接基类];基类的基类甚至更高层的基类称为[间接基类]
- 继承与派生是为了提高代码的重用性和可扩充性。【好处】
- 通过继承实现设计与代码的重用,通过派生实现当新问题出现并且不能用原有设计解决时进行对原有类的改造【目的】
- 派生类的生成过程:
1.吸收基类成员——吸收除去构造函数和析构函数之外的所有成员
2.改造基类成员——如果派生类声明了一个和某些基类成员同名的新成员,派生类就会隐藏外层同名成员,这被称为[同名隐藏]
3.添加新成员 - [公有继承]:基类的公有成员public和保护类成员protected的访问属性在派生类中不变,而基类的私有成员private不可以直接访问
- [私有继承]:基类的公有成员public和保护类成员protected在派生类中以私有成员身份出现,而基类的私有成员private不可以直接访问(即都作为派生类的私有成员)
- [保护继承]:基类的公有成员public和保护成员protected都以保护类成员身份出现在派生类中,基类私有成员private不可以直接访问
二、3种继承方式的比较(public,private,protected)
【公有继承】【7-1】
代码
//从基类继承的public、protected类型都可使用,private不能使用
#include<iostream>
using namespace std;
class Point {
public:
void initPoint(float x = 0, float y = 0) {
this->x = x;
this->y = y;
}
void move(float offX, float offY) {
x += offX;
y += offY;
}
float getX() const{ return x; }
float getY() const{ return y; }
private:
float x, y;
};
class Rectangle:public Point {
public:
void initRectangle(float x, float y, float w, float h) {
initPoint(x, y); //调用基类公有数据成员
this->h = h;
this->w = w;
}
float getW() const { return w; }
float getH() const { return h; }
private: //新增私有数据成员
float w, h;
};
int main() {
Rectangle rect;
rect.initRectangle(2, 3, 20, 10);
rect.move(3, 2);
cout << "The data of rect(x,y,w,h):" << endl;
cout << rect.getX() << ","
<< rect.getY() << ","
<< rect.getW() << ","
<< rect.getH() << endl;
return 0;
}
运行截图
【私有继承】【7-2】
代码
/*7-2*//*私有继承*/
#include<iostream>
using namespace std;
class Point {
public:
void initPoint(float x = 0, float y = 0) {
this->x = x;
this->y = y;
}
void move(float offX, float offY) {
x += offX;
y += offY;
}
float getX() const{ return x; }
float getY() const{ return y; }
private:
float x, y;
};
class Rectangle:private Point { //*****************
public:
void initRectangle(float x, float y, float w, float h) {
initPoint(x, y); //调用基类公有数据成员
this->h = h;
this->w = w;
}
void move(float offX, float offY) {
Point::move(offX, offY); //***********************
}
float getX() const { return Point::getX(); } //********************
float getY() const { return Point::getY(); } //********************
float getW() const { return w; }
float getH() const { return h; }
private: //新增私有数据成员
float w, h;
};
int main() {
Rectangle rect;
rect.initRectangle(0, 0, 20, 10);
rect.move(3, 2);
cout << "The data of rect(x,y,w,h):" << endl;
cout << rect.getX() << ","
<< rect.getY() << ","
<< rect.getW() << ","
<< rect.getH() << endl;
return 0;
}
运行截图
【保护继承】【7-3】
- 基类的公有成员和保护成员都以保护类成员身份出现在派生类中,基类私有成员不可以直接访问
- 派生类的其他成员可以直接访问从基类继承来的公有成员和保护成员,但在类的外部通过派生类的对象无法直接访问他们
- 如果B是A的派生类,B的成员函数只能通过B的对象访问A中定义的protected成员,而不能通过A的对象访问A中的protected对象
代码
#include
#include
using namespace std;
class A {
public:
int a;
A() {
a1 = 1;
a2 = 2;
a3 = 3;
a = 4;
}
void fun() {
cout << a << endl; //正确
cout << a1 << endl; //正确
cout << a2 << endl; //正确
cout << a3 << endl; //正确
}
public:
int a1;
protected:
int a2;
private:
int a3;
};
class B : protected A {
public:
int a;
B(int i) {
A();
a = i;
}
void fun() {
cout << a << endl; //正确,public成员。
cout << a1 << endl; //正确,基类的public成员,在派生类中变成了protected,可以被派生类访问。
cout << a2 << endl; //正确,基类的protected成员,在派生类中还是protected,可以被派生类访问。
cout << a3 << endl; //错误,基类的private成员不能被派生类访问。
}
};
int main() {
B b(10);
cout << b.a << endl; //正确。public成员
cout << b.a1 << endl; //错误,protected成员不 能在类外访问。
cout << b.a2 << endl; //错误,protected成员不能在类外访问。
cout << b.a3 << endl; //错误,private成员不能在类外访问。
system("pause");
return 0;
}
运行截图
三、派生类的构造函数执行顺序浅析
【构造函数】
- 构造派生类对象时,需要对基类的成员对象和新增成员对象进行初始化
- 一般语法为:
派生类名::派生类名(参数表):基类名1(基类1初始化列表),...,基类n(基类n初始化列表),成员对象1(成员对象1初始化列表)...
{
派生类构造函数的其他初始化操作;
}
- 如果对基类进行初始化时,需要调用基类的带有形参表的构造函数时,必须声明构造函数
- 派生类构造函数执行的一般次序
1.调用基类构造函数
2.对派生类新增的成员对象初始化,调用顺序按照它们在类中的声明顺序
3.执行派生类的构造函数内容
代码
//7-4 派生类构造函数,多继承,含有内嵌对象
#include<iostream>
using namespace std;
class B1 { //基类B1,构造函数有参数
public:
B1(int i) {
cout << "构造函数B1" << i << endl;
}
};
class B2 { //基类B2,构造函数有参数
public:
B2(int j) {
cout << "构造函数B2" << j << endl;
}
};
class B3 { //基类B3,构造函数无参数
public:
B3() {
cout << "构造函数B3*" << endl;
}
};
class Derived :public B2, public B1, public B3 {
//声明派生类,顺序为B2,B1,B3
public:
Derived(int a,int b,int c,int d):B1(a),menber2(d),menber1(c),B2(b){}
//注意类名的个数与顺序,注意成员对象名的个数与顺序
private:
B1 menber1;
B2 menber2;
B3 menber3;
};
int main() {
Derived obj(1, 2, 3, 4);
return 0;
}
运行截图
代码解析
1.关于Derived类构造函数的执行情况:先调用基类的构造函数,然后调用内嵌对象的构造函数,又因基类的调用顺序按照派生类的定义顺序,所以先B2,再是B1最后B3,而内嵌对象的调用顺序是按照成员在类中声明的顺序,所以先B1,后B2、B3
2.因为B3的构造函数没有参数,所以基类B3和基类B3的类成员对象menber3就不必列出