继承与派生:
{
继承 即从已有类基础上创建新类 新类可从一个或多个类继承数据成员和成员函数
可重新定义或添加新的数据 可改变基类成员在派生类中的访问属性
已有类称为基类或父类 新类称为派生类或子类
派生类对基类成员的访问:
内部访问:由派生类中新增的成员函数对基类继承来的成员进行访问
对象访问:在派生类的外部 通过派生类的对象对基类继承来的成员进行访问
一般格式:{
派生类名(参数表) : 基类名(参数表)
{
派生类新增数据成员初始化
}
含子对象构造函数:
派生类名(参数总表) : 基类名(参数表0), 子对象1(参数表1), ... , 子对象n(参数表n)
{
派生类新增成员初始化
}
}
派生类可声明与基类成员同名的成员 在无虚函数时 若派生类中定义了与基类成员同名的成员
则派生类成员覆盖基类的同名成员 在派生类中使用该名字代表访问派生类中声明的成员
若想在派生类中使用与基类同名的成员 须在成员名之前加上 基类名及作用域标识符'::' 即:{
基类名::函数名(参数表);
eg:{
class B : private A{
private:
int Bb;
public:
B(int a, int b) : A(a) {
Bb = b;
}
A::show; // 访问声明
};
}
}
数据成员也可以使用访问声明
访问声明中只含不带类型和参数的函数名或变量名
访问声明不能改变成员在基类中的访问属性
对于基类的重载函数名 访问声明将对基类中所有同名函数其起作用
多继承:{
形式如下:
class 派生类名 : 继承方式1 基类名1, ... , 继承方式n 基类名n
{
...
}
默认继承方式为private
}
#include <iostream>
using namespace std;
class Person{
private:
string name;
int age;
int number;
public:
Person(string na, int ag, int num) {
name = na;
age = ag;
number = num;
}
~Person() {
}
void show_person(void) {
cout << "name is: " << name << " age is: " << age << " number is: " << number << endl;
}
};
class Student: public Person{
private:
string major;
public:
Student(string na, int ag, int num, string maj) : Person(na, ag, num) {
major = maj;
}
~Student() {
}
void show_student(void) {
Person::show_person();
cout << " major is: " << major << endl;
}
};
int main()
{
Student stu("Tom", 18, 2019001, "Computer Science");
stu.show_student();
return 0;
}
虚基类:{
一般形式 :
class 派生类名 : virtual 继承方式 类名{
...
};
}
赋值兼容规则:{ '条件派生类从其基类公有派生'
在任何需要基类对象的地方 都可用子类的对象代替 但只能使用从基类继承来的成员
假设有如下类:{
class Base{
...
};
class Derived : public Base{
...
};
}
派生类对象可以赋值给基类对象,即用派生类对象中从基类继承来的数据成员,逐个赋值给基类对象的数据成员
eg:{
Base b;
Derived d;
b = d;
}
派生类对象可以初始化基类对象的引用
eg:{
Derived d;
Base &b = d;
}
派生类对象的地址可以赋值给指向基类对象的指针
eg:{
Derived d;
Base *p = &d;
}
}
}
#include <iostream>
using namespace std;
class Base{
protected:
int a;
public:
Base() {
a = 5;
cout << "Base = " << a << endl;
}
};
class Base1: virtual public Base{
public:
Base1() {
a += 5;
cout << "Base1 = " << a << endl;
}
};
class Base2: virtual public Base{
public:
Base2() {
a += 20;
cout << "Base2 = " << a << endl;
}
};
class Derived: public Base1, public Base2{
public:
Derived() {
cout << "the Base1 = " << Base1::a << endl;
cout << "the Base2 = " << Base2::a << endl;
}
};
int main()
{
Derived objd;
return 0;
}
多态性与虚函数:
{ '一个接口,多种方法'
即不同对象收到相同消息 产生不同动作
静态连编就是在编译阶段完成的连编 动态连编时运行阶段完成的
编译时的多态是通过静态连编来实现 运行时的多态是用动态连编实现
编译时多态性主要是通过函数重载和运算符重载实现 运行时多态性主要是通过虚函数来实现
虚函数:{
形式如下:
virtual 返回值类型 函数名(参数表)
{
函数体
}
在基类中的某个成员函数被声明为虚函数后,此虚函数就可以在一个或多个派生类中被重新定义
虚函数在派生类中重新定义时 其函数原型 包括返回类型 函数名 参数个数 参数类型的顺序 都必须与基类中的原型完全相同
若在派生类中 没有用virtual显示给出虚函数说明 则根据以下规则判断 该函数是否为虚函数:
与基类的虚函数是否有相同的名称 参数个数以及对应的参数类型 返回类型或者满足赋值兼容的指针 引用型的返回类型
通过定义虚函数来使用多态性机制时 派生类必须从它的基类公有派生
虚函数必须是其所在类的成员函数 而不能是友元函数 也不能是静态成员函数 因为虚函数调用要靠特定的对象来决定该激活哪个函数
内联函数不能是虚函数 内联函数是不能在运行中动态确定其位置的
构造函数不能是虚函数 析构函数可以是虚函数 且通常说明为虚函数
在一个派生类中重新定义基类的虚函数是函数重载的另一种形式
}
#include <iostream>
#include <string>
using namespace std;
class Family{
private:
string flower;
public:
Family(string name = "flowers") : flower(name) {
}
string get_flower(void) {
return flower;
}
virtual void like_flower(void) {
cout << "they like different flowers" << endl;
}
};
class Child: public Family{
public:
Child(string name = "camellia"): Family(name) {
}
void like_flower(void) {
cout << " she likes " << get_flower() << endl;
}
};
class Parent: public Family{
public:
Parent(string name = "rose"): Family(name) {
}
void like_flower(void) {
cout << " he likes " << get_flower() << endl;
}
};
int main()
{
Family *F;
Family y;
Child c;
Parent p1;
F = &y;
F->like_flower();
F = &c;
F->like_flower();
F = &p1;
F->like_flower();
return 0;
}
虚析构函数:{
virtual ~类名() {
...
}
如果将基类的析构函数定义为虚函数 由该类所派生的所有派生类的析构函数也都自动成为虚函数
}
#include <iostream>
#include <string>
using namespace std;
class Base{
public:
// ~Base() { //此时系统仅调用基类的析构函数
virtual ~Base() {
cout << "调用基类Base的析构函数" << endl;
}
};
class Derived: public Base{
public:
~Derived() {
cout << "调用派生类Derived的析构函数" << endl;
}
};
int main()
{
Base *p;
p = new Derived();
delete p;
return 0;
}
纯虚函数 {
纯虚函数是在声明虚函数时被'初始化为0的函数' 声明纯虚函数的一般形式如下
virtual 返回值类型 函数名(参数表) = 0;
声明为纯虚函数后 基类中就不再给出程序的实现部分 纯虚函数的作用是在基类中为其派生类保留一个函数的名字 以便派生类根据需要重新定义
}
抽象类 {
如果一个类至少有一个纯虚函数 那么就称该类为抽象类
由于抽象类中至少包含一个没有定义功能的纯虚函数 抽象类只能作为其他类的基类来使用 不能建立抽象类对象
不允许从具体类派生出抽象类 具体类即 不包含纯虚函数的普通类
抽象类不能用作函数的参数类型 函数的返回类型 或是显式转换的类型
可以声明指向抽象类的指针或引用 此指针可以指向它的派生类 进而实现多态性
如果派生类中没有定义纯虚函数的实现 而派生类中只是继承基类的纯虚函数 则这个派生类仍然是一个抽象类 反之则是可以建立对象的具体类
}
#include <iostream>
using namespace std;
class Figure{
protected:
double zozoX, zozoY;
public:
Figure(double x, double y) : zozoX(x), zozoY(y) {}
virtual void getArea() // 基类Figure的虚函数
{
cout << "no area for this class" << endl;
}
};
class Triangle: public Figure{
public:
Triangle(double x, double y) : Figure(x, y) {}
void getArea() // 重写基类Figure的虚函数
{
cout << "area of triangle is: " << 0.5 * zozoX * zozoY << endl;
}
};
class Square: public Figure{
public:
Square(double x, double y) : Figure(x, y) {}
void getArea() // 重写基类Figure的虚函数
{
cout << "area of square is: " << zozoX * zozoY << endl;
}
};
class Circle: public Figure{
public:
Circle(double x, double y) : Figure(x, y) {}
void getArea() // 重写基类Figure的虚函数
{
cout << "area of circle is: " << 3.14 * zozoX * zozoX << endl;
}
};
int main()
{
Figure *f;
Triangle t(3, 4);
Square s(5, 5);
Circle c(6, 6);
f = &t;
f->getArea();
f = &s;
f->getArea();
f = &c;
f->getArea();
return 0;
}
}