相关内容:
- 面向对象程序设计中最重要的一个概念是继承。继承允许我们依据另一个类来定义一个类,这使得创建和维护一个应用程序变得更容易。
这样做,也达到了重用代码功能和提高执行效率的效果。 - 当创建一个类时,您不需要重新编写新的数据成员和成员函数,只需指定新建的类继承了一个已有的类的成员即可。这个已有的类称
为基类,新建的类称为派生类。 - 继承代表了 is a 关系。例如,哺乳动物是动物,狗是哺乳动物,因此,狗是动物,等等。
基类 & 派生类:
一个类可以派生自多个类,这意味着,它可以从多个基类继承数据和函数。定义一个派生类,我们使用一个类派生列表来指定基类。
类派生列表以一个或多个基类命名,形式如下:其中,访问修饰符1
class derived-class: access-specifier base-class
access-specifier
是 public、protected 或 private 其中的一个,base-class
是之前定义过的某
个类的名称。如果未使用访问修饰符access-specifier
,则默认为private
。访问控制和继承:
派生类可以访问基类中所有的非私有成员。因此基类成员如果不想被派生类的成员函数访问,则应在基类中声明为 private。我们可以
根据访问权限总结出不同的访问类型,如下所示:访问 public protected private 同一个类 yes yes yes 派生类 yes yes no 外部的类 yes no no 一个派生类继承了所有的基类方法,但下列情况除外: - 基类的构造函数、析构函数和拷贝构造函数。
- 基类的重载运算符。
- 基类的友元函数。
虚函数:
当把基类的某个成员函数声明为虚函数后,允许在其派生类中对该函数重新定义,赋予它新的功能,并且可以通过指向基类的指针指向同一
类族中不同类的对象,从而调用其中的同名函数。由虚函数实现的动态多态性就是:同一类族中不同类的对象,对同一函数调用作出不同的响应。
虚函数的使用方法是:
- 在基类用
virtual
声明成员函数为虚函数。
这样就可以在派生类中重新定义此函数,为它赋予新的功能,并能方便地被调用。在类外定义虚函数时,不必再加virtual
。 - 在派生类中重新定义此函数,要求函数名、函数类型、函数参数个数和类型全部与基类的虚函数相同,并根据派生类的需要重新定义函数体。
C++规定,当一个成员函数被声明为虚函数后,其派生类中的同名函数都自动成为虚函数。因此在派生类重新声明该虚函数时,可以加virtual
,
也可以不加,但习惯上一般在每一层声明该函数时都加virtual,使程序更加清晰。如果在派生类中没有对基类的虚函数重新定义,则派生类简
单地继承其直接基类的虚函数。 - 定义一个指向基类对象的指针变量,并使它指向同一类族中需要调用该函数的对象。
- 通过该指针变量调用此虚函数,此时调用的就是指针变量指向的对象的同名函数。
通过虚函数与指向基类对象的指针变量的配合使用,就能方便地调用同一类族中不同类的同名函数,只要先用基类指针指向即可。如果指针不
断地指向同一类族中不同类的对象,就能不断地调用这些对象中的同名函数。这就如同前面说的,不断地告诉出租车司机要去的目的地,然后
司机把你送到你要去的地方。
需要说明;有时在基类中定义的非虚函数会在派生类中被重新定义,如果用基类指针调用该成员函数,则系统会调用对象中基类部分的成员函数;
如果用派生类指针调用该成员函数,则系统会调用派生类对象中的成员函数,这并不是多态性行为(使用的是不同类型的指针),没有用到虚函数的功能。
以前介绍的函数重载处理的是同一层次上的同名函数问题,而虚函数处理的是不同派生层次上的同名函数问题,前者是横向重载,后者可以理解
为纵向重载。但与重载不同的是:同一类族的虚函数的首部是相同的,而函数重载时函数的首部是不同的(参数个数或类型不同)。代码相关内容:
- 基类:
virtual
函数;protected
函数; - 派生类:类派生列表;重定义
virtual
函数;可以访问基类的public
和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
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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
using namespace std;
class Animal
{
// 成员略
};
// 下面的 : 就表示继承或者派生;
class Dog : public Animal
{
// 成员略
};
class Cat : public Animal
{
// 成员略
};
class Item_base
{
public:
int x;
Item_base(const std::string &book = "",
double sales_price = 0.0):isbn(book),price(sales_price){}
std::string book() const
{
return isbn;
}
// virtual:定义为虚函数,则在派生类中可以对其进行重新定义;
virtual double net_price(size_t n) const
{
return n * price;
}
private:
string isbn;
protected:
double price;
};
class Bulk_item : public Item_base
{
public:
// 派生类的构造函数;
Bulk_item(const std::string &book="",double sales_price=0.0,size_t qty=0,
double disc_rate = 0.0):Item_base(book,sales_price),min_qty(qty),discount(disc_rate){}
void test()
{
// cout << x << endl;
cout << price << endl; // 成员函数,可以使用父类中的protected成员;
// cout << isbn << endl; // 但是不能使用父类中的private成员;
}
void test2(const Bulk_item &d, const Item_base &b)
{
//cout << d.x << endl;
cout << d.price << endl;
//cout << b.x << endl; // public成员没问题;
//cout << b.price << endl; // 错误;protected成员可以在类的内部使用或者是对它的友元使用,可以被继承,但是不能被调用;
}
// 只有虚函数才能够重写;
double net_price(size_t cnt) const
{
if (cnt >= min_qty) //如果购买的数量大于最小打折数量,则打折;
return cnt * (1 - discount) *price;
else
return cnt * price;
}
private:
size_t min_qty;
double discount;
};
int main()
{
Animal a;
Dog d;
Item_base item("asdf", 9.9);
cout << item.book() << "," << item.net_price(10) << endl;
// cout << item.x << endl;
// cout << item.isbn << endl; // 错误;private成员不能在类外部使用;
// cout << item.price << endl; // 错误;protected成员可以在继承的类中的成员函数中使用,但是普通函数不行;
Bulk_item item2("asdf", 9.9, 10, 0.12);
cout << item2.book() << "," << item2.net_price(10) << endl;
// cout << item2.x << endl;
item2.test();
item2.test2(item2, item);
return 0;
}代码执行结果:
参考链接:
C++ 继承
什么是C++虚函数、虚函数的作用和使用方法