0%

C++类的继承和多态

类的继承

简单介绍

C++是一种面向对象的语言,最重要的一个目的就是——提供可重用的代码,而类继承就是C++提供来扩展和修改类的方法。类继承就是从已有的类中派生出新的类,派生类继承了基类的特性,同时可以添加自己的特性。实际上,类与类之间的关系分为三种:代理、组合和继承。以下是三种关系的图解:(为了更好的理解)

img

基类可以派生出派生类,基类也叫做“父类”,派生类也称为“子类”。

​ 那么,派生类从基类中继承了哪些东西呢?分为两个方面:1. 变量——派生类继承了基类中所有的成员变量,并从基类中继承了基类作用域,即使子类中的变量和父类中的同名,有了作用域,两者也不冲突。2.方法——派生类继承了基类中除去构造函数、析构函数以外的所有方法。子类除了具有基类的所有成员(包括成员变量和成员函数)之外,还可以添加自己特有的成员(包括变量和函数)

继承方式和访问限定符

继承方式:public, protected, private
结构类型struct默认是public继承
类类型class默认是private继承

image-20220603191138674

总的来说,父类成员的访问限定符通过继承派生到子类中之后,访问限定符的权限小于、等于原权限。其中,父类中的private成员只有父类本身及其友元可以访问,通过其他方式都不能进行访问,当然就包括继承。protected多用于继承当中,如果对父类成员的要求是——子类可访问而外部不可访问,则可以选择protected继承方式

虽然有的成员变量无法访问,但都继承下来了,也占空间。

派生类对象的构造方式

前面也提到,派生类将基类中除去构造函数和析构函数的其他方法继承了过来,那么对于派生类对象中自己的成员变量和来自基类的成员变量,它们的构造方式是怎样的呢?

答案是:在定义子类对象时, 先自动调用基类的构造函数,然后再自动调用子类本身的构造函数 (正序构造)。在释放子类对象时, 先自动调用子类本身的析构函数,然后再自动调用基类的析构函数(逆序析构)符合栈的结构特点

如下展示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include<iostream>
using namespace std;

class Shape
{
public:
Shape()
{
cout<<"Shape()"<<endl;
}
~Shape()
{
cout<<"~Shape()"<<endl;
}
};

class Rectangle:public Shape
{
public:
Rectangle()
{
cout<<"Rectangle:public Shape"<<endl;
}
~Rectangle()
{
cout<<"~Rectangle:public Shape"<<endl;
}
};

int main()
{
Rectangle r;
return 0;
}

结果

1
2
3
4
Shape()
Rectangle:public Shape
~Rectangle:public Shape
~Shape()

类的多态

多态:在具有继承关系的多个对象中,通过基类指针(或基类引用)来调用不同子类中的同名成员函数,自动(当然也可以手动,例如cout<<a.rectangle::area()<<'\n'<<a.area();,其中a是用rectangle的子类创建的对象)根据不同子类的类型,来实现不同的功能(呈现不同的形态)
通常使用虚函数(virtual)来实现多态

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#include<iostream>
using namespace std;

class Shape
{
private:
double s;//area
double c;//circumference
public:
void setArea(double ss);//statement
virtual double getArea();
void setCircumference(double cc);
double getCircumference();
};

class Rectangle:public Shape
{
private:
double length;
double width;
public:
void setLength(double len);
void setWidth(double wid);
virtual double getArea();//更改父类中函数定义

};

int main()
{
Rectangle rect;
double len,wid;
cout<<"Enter length and width:";
cin>>len>>wid;
rect.setLength(len);
rect.setWidth(wid);
cout<<rect.getArea();

return 0;
}

void Shape::setArea(double ss)//definition
{
s=ss;
}

double Shape::getArea()
{
return s;
}

void Shape::setCircumference(double cc)
{
c=cc;
}

double Shape::getCircumference()
{
return c;
}

void Rectangle::setLength(double len)
{
length=len;
}

void Rectangle::setWidth(double wid)
{
width=wid;
}
double Rectangle::getArea()//此处不再加virtual
{
return length*width;
}

补充:类中指针的巧妙运用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include<iostream>
using namespace std;
class Shape
{
public:
virtual void draw()
{
cout<<"Shape"<<endl;
}
};

class Circle:public Shape
{
public :
virtual void draw()
{
cout<<"Circle"<<endl;
}
};

class Rectangle:public Shape
{
public:
virtual void draw()
{
cout<<"Rectangle"<<endl;
}
};

void drawShape1(Shape *x)//指针传值
{
x->draw();
}

void drawShape2(Shape &x)//引用传值
{
x.draw();
}

int main()
{
Shape s;
Circle c;
Rectangle r;

cout << "-------------------------" << endl;
//最基本方式
Shape *pShape;

pShape = &s;
pShape->draw();

pShape = &c;
pShape->draw();

pShape = &r;
pShape->draw();


cout << "-------------------------" << endl;
//指针传值
drawShape1(&s);
drawShape1(&c);
drawShape1(&r);

cout << "-------------------------" << endl;
//引用传值
drawShape2(s);
drawShape2(c);
drawShape2(r);

cout << "-------------------------" << endl;

return 0;
}

指针也可以用来创建子类对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <iostream>
using namespace std;

class BaseCalculator {
public:
int m_A;
int m_B;
// write your code here......
virtual int getResult()
{
return 0;//别忘记返回值
}
};

// 加法计算器类
class AddCalculator : public BaseCalculator {
// write your code here......
public:
virtual int getResult()
{
return m_A+m_B;
}

};

// 减法计算器类
class SubCalculator : public BaseCalculator {
// write your code here......
public:
virtual int getResult()
{
return m_A-m_B;
}

};


int main() {

BaseCalculator* cal = new AddCalculator;//下面是精髓
cal->m_A = 10;
cal->m_B = 20;
cout << cal->getResult() << endl;
delete cal;

/*以上代码等于下面注释
AddCalculator cal;
cal.m_A=10;
cal.m_B=20;
cout << cal.getResult() << endl;
*/

cal = new SubCalculator;
cal->m_A = 20;
cal->m_B = 10;
cout << cal->getResult() << endl;
delete cal;

return 0;
}