C++类的继承
1、继承
1.1 继承介绍
子继承父中的某些属性与行为
例如:
比如:
学生:姓名 年龄 身高 学生编号
吃饭 睡觉 学习
老师:姓名 年龄 身高 教师编号
吃饭 睡觉 备课
职工:姓名 年龄 身高 职工编号
吃饭 睡觉 工作
****
共同的东西:
人类:
属性:姓名,年龄,身高
方法:吃饭,睡觉
可以让学生类/教师类/员工类 继承 自 人类
1.2 继承的使用
发生在类与类之间,通过继承机制,可以利用已有的数据类型来定义新的数据类型,
所定义的新的数据不仅拥有新定义的成员,还有继承来的成员。
已存在用来派生其他类的类叫基类或父类,由已存在的类派生出来的类叫派生类或者子类。
目的:类复用,提高效率,缩短开发周期。
继承的分类:单继承 、 多继承
1.3 继承的步骤
- 吸收基类成员
- 覆盖基类同名成员
- 添加新成员
ps:析构、构造函数不能继承
1.4 派生类(子类)的定义
1.4.1 单继承:只有一个基类(父类)
单继承定义格式:
class 子类名:继承方式 父类名
{
//新成员.....
};
继承方式:将父类看做子类的成员,当子类创建对象时,以何种权限实现对其成员的访问。
- public:父类公有成员和保护成员保持原有的状态,私有不能在子类中访问
- private:父类公有成员和保护成员都作为子类的私有成员
- protected:父类公有成员和保护成员都作为子类的保护成员
例如:Point 和 Point3D —— 单继承
// Point -- 父类
class Point {
private:
int xp;
int yp;
public:
Point(int x,int y):xp(xp),yp(yp) {
}
int getXP() {
return xp;
}
int getYP() {
return yp;
}
};
// Point3D -- 子类
class Point3D:public Point
{
private:
// Point temp; //相当于继承了 int xp ,int yp
int zp;
public:
Point3D(int x=0,int y=0,int z=0):Point(x,y),zp(z) //初始化必需使用父类构造函数
{
}
void show()
{
cout << "xp" << getXP() << ",yp" << getYP() << ",zp" << zp << endl;
}
};
int main()
{
Point3D a(1,2,3);
a.show();
return 0;
}
ps:在子类初始化的时候自动调用父类的构造函数只能用初始化表达式的形式
设计类的时候一般属性可以设置为private protected public,但是一般成员函数设置成public.
1.4.2 多继承
多继承定义格式:
class 子类名:继承方式 父类名,继承方式 父类名......
{
};
// A -- 父类
class A
{
public:
int ax;
A(int x=0)
{
ax = x;
}
void printA()
{
cout << "ax:" << ax << endl;
}
};
// B -- 父类
class B
{
public:
int bx;
B(int x=0)
{
bx = x;
}
void printB()
{
cout << "bx:" << bx << endl;
}
};
class C:public A,public B //继承多个类
{
public:
C(int x,int y):A(x),B(y)
{
}
};
多继承可能一到的问题
- 多继承二义性 – 函数命名冲突 – 调用的时候 加 类名::指定是哪一个类里面的成员函数
- 共基类 – 多个共基类拷贝 – 加 类名:: 或 虚继承
例一:多继承二义性
// A -- 父类
class A
{
public:
int ax;
A(int x=0)
{
ax = x;
}
void printA()
{
cout << "ax:" << ax << endl;
}
void show()
{
cout << "我是Ashow" << endl;
}
};
// B -- 父类
class B
{
public:
int bx;
B(int x=0)
{
bx = x;
}
void printB()
{
cout << "bx:" << bx << endl;
}
void show()
{
cout << "我是Bshow" << endl;
}
};
class C:public A,public B
{
public:
C(int x,int y):A(x),B(y)
{
}
};
int main()
{
C obj(1,5);
obj.printA();
obj.printB();
obj.ax = 100;
obj.printA();
// obj.show(); 报错:有歧义,不知道执行继承哪一个
obj.A::show();
return 0;
}
例二:虚继承解决共父类的二义性问题
class D
{
public:
int a;
void show()
{
cout << "我是父类Dshow" << endl;
}
};
class A:virtual public D
{
};
class B:virtual public D
{
};
class C:public A,public B
{
};
int main()
{
C obj;
obj.show();
return 0;
}
虚继承:使共同基类只产生一个拷贝,只对第一个调用有效,对其他派生类都是虚假的,没有调用构造函数。
1.5 构造函数和析构函数执行顺序
构造函数和析构函数时不能继承的,只能自己使用自己的构造函数和析构函数
调用基类的构造函数必须在派生类的构造函数中使用初始化表达式的形式
构造函数执行顺序:先基类再派生类
析构函数执行顺序:先派生类再基类
1.6 类型适应
子类类适用于父类,子类的对象、指针、引用适用于父类对象、指针、引用
父类的对象、指针、引用 = 子类的对象 、指针 、 引用赋值给
class A
{
public:
int xp;
A(int x=0)
{
xp = x;
}
void show()
{
cout << "xp" << xp << endl;
}
};
class B:public A
{
public:
int yp;
B(int x=0,int y=0):A(x)
{
yp = y;
}
void show()
{
cout << "xp:" << xp << ",yp" << yp << endl;
}
};
int main()
{
A a(5);
B b(1,5);
a.show();
b.show();
// 父类的对象 = 子类的对象
a = b;
a.show();
// 使用父类的指针 指向子类对象
A *t = &b;
t->show();
// 父类的引用 引用子类的对象
A &k = b;
k.show();
return 0;
}