- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章详解C++基础——类继承中方法重载由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
1、前言 。
在上一篇C++基础博文中讨论了C++最基本的代码重用特性——类继承,派生类可以在继承基类元素的同时,添加新的成员和方法。但是没有考虑一种情况:派生类继承下来的方法的实现细节并不一定适合派生类的需求,此时派生类需要重载集成方法.
2、重载方法及虚函数 。
我们讨论《C++ Primer Plus》中的如下场景:银行记录客户信息,包括客户姓名、当前余额。客户这一类别当然能够创建客户对象、存款、取款以及显示信息。银行需要特殊记录具有透支权限的客户,因此这一类别的客户要额外记录透支上限、透支贷款利率以及当前透支总额。此外,取款和显示信息两个操作必须考虑客户的透支情况。综上,具有透支权限的客户是客户这一基类的派生类,派生类中不但需要添加新的成员,还要重载两个继承方法.
类声明代码:
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
|
#ifndef BRASS_H_
#define BRASS_H_
#include <string>
class
Brass
{
private
:
std::string fullName;
long
acctNum;
double
balance;
public
:
Brass(
const
std::string& s =
"Nullbody"
,
long
an = -1,
double
ba = 0.0);
//default constructor
void
Deposit(
double
amt);
double
Balance()
const
;
virtual
void
Withdraw(
double
amt);
//virtual function
virtual
void
ViewAcct()
const
;
virtual
~Brass() {}
//使用虚析构函数确保先调用继承类析构函数
};
//brass plus account class
class
BrassPlus:
public
Brass
{
private
:
double
maxLoan;
double
rate;
double
owesBank;
public
:
BrassPlus(
const
std::string& s =
"Nullbody"
,
long
an = -1,
double
bal = 0.0,
double
ml = 500,
double
r = 0.11125);
BrassPlus(
const
Brass& ba,
double
ml = 500,
double
r = 0.11125);
virtual
void
ViewAcct()
const
;
virtual
void
Withdraw(
double
amt);
void
ResetMax(
double
m) {maxLoan = m;}
//inline function
void
ResetRate(
double
r) {rate = r;}
void
ResetOwes() {owesBank = 0;}
};
#endif
brass.h
|
类方法定义代码:
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
|
#include"brass.h"
#include <iostream>
using
std::cout;
using
std::endl;
using
std::string;
//brass methods
Brass::Brass(
const
string& s,
long
an,
double
bal)
{
fullName = s;
acctNum = an;
balance = bal;
}
void
Brass::Deposit(
double
amt)
{
if
(amt < 0)
cout <<
"Negative deposit not allowed;"
<<
"deposit is cancelled.\n"
;
else
balance += amt;
}
void
Brass::Withdraw(
double
amt)
{
if
(amt < 0)
cout <<
"Withdrawal amount must be positive;"
<<
"withdrawal canceled.\n"
;
else
if
(amt <= balance)
balance -= amt;
else
cout <<
"Withdrawal amount of $"
<< amt
<<
"exceeds your balance.\n"
<<
"Withdrawal canceled.\n"
;
}
double
Brass::Balance()
const
{
return
balance;
}
void
Brass::ViewAcct()
const
{
cout <<
"Client: "
<< fullName << endl;
cout <<
"Account Number: "
<< acctNum << endl;
cout <<
"Balance: $"
<< balance << endl;
}
//brassPlus methods
BrassPlus::BrassPlus(
const
string& s,
long
an,
double
bal,
double
ml,
double
r):Brass(s,an,bal)
{
maxLoan = ml;
owesBank = 0.0;
rate = r;
}
BrassPlus::BrassPlus(
const
Brass& ba,
double
ml,
double
r):Brass(ba)
{
maxLoan = ml;
owesBank = 0.0;
rate = r;
}
//redefine viewacct()
void
BrassPlus::ViewAcct()
const
{
Brass::ViewAcct();
cout <<
"Maximum loan: $"
<< maxLoan << endl;
cout <<
"Owed to bank: $"
<< owesBank << endl;
}
void
BrassPlus::Withdraw(
double
amt)
{
double
bal = Balance();
if
(amt <= bal)
Brass::Withdraw(amt);
else
if
(amt <= bal + maxLoan - owesBank)
// 已欠 + 此欠 ≤ maxLoan
{
double
advance = amt - bal;
owesBank += advance * (1.0+rate);
cout <<
"Bank advance: $"
<< advance << endl;
cout <<
"Finance charge: $"
<< advance*rate << endl;
Deposit(advance);
Brass::Withdraw(amt);
// return to zero
}
else
cout <<
"Credit limit exceeded. Transcation cancelled.\n"
;
}
brass.cpp
|
上述代码多了一个新的语法特性:虚函数(virtual function)。当基类声明中函数前加virtual,表示该函数为虚函数。区别在于当调用者是引用或者指针时,调用的是基类方法,还是派生类重载后的方法。具体区别我们后边在讨论。重中之重在于虚析构函数的意义。如果程序中使用delete删除占用的动态内存,且用于索引内存地址的指针类型是基类,那么即使该指针指向的是一个派生类对象,此时仅基类析构函数被调用。 我们着重观察brassPlus类重载的方法WithDraw有什么变化。这类客户由于具有透支权限,在取款时肯定要考虑欠款情况。若欲取出金额≤存储金额,则直接调用基类方法WithDraw,把存储金额减小;若欲取出金额大于存储金额,就必须进一步分析欠款情况。已欠款+此次欠款≤透支额度时,取款操作才有效。因此:owes+(amt - balance) ≤ maxLoan,进一步变形为:amt ≤ balance+maxLoan-owes.
3、应用程序示例及结果分析 。
现在看看应用程序代码和显示结果。APP代码:
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
|
#include <iostream>
#include "brass.h"
int
main()
{
using
std::cout;
using
std::endl;
Brass Piggy(
"Porcelot Pigg"
,381299,4000.00);
BrassPlus Hoggy(
"Horatio Hogg"
,382288,3000.00);
Piggy.ViewAcct();
cout << endl;
Hoggy.ViewAcct();
cout << endl;
cout <<
"Depositing $1000 into the Hogg Account:\n"
;
Hoggy.Deposit(1000.00);
cout <<
"New balance: $"
<<Hoggy.Balance() <<endl;
cout << endl;
cout <<
"Withdrawing $4200 from the Pigg Account:\n"
;
Piggy.Withdraw(4200.00);
cout <<
"Pigg account balance: $"
<< Piggy.Balance() << endl;
cout << endl;
cout <<
"Withdrawing $4200 from the Hogg Account:\n"
;
Hoggy.Withdraw(4200.00);
Hoggy.ViewAcct();
cout << endl;
Brass dom(
"Dominic Banker"
,11224,4183.45);
BrassPlus dot(
"Dorothy Banker"
,12118,2592.00);
Brass& b1_ref = dom;
Brass& b2_ref = dot;
//use BrassPlus::ViewAcct() function
b1_ref.ViewAcct();
cout << endl;
b2_ref.ViewAcct();
cout << endl;
return
0;
}
usebrass.cpp
|
打印结果:
Pigg和Hogg分别是基类和派生类对象。当两种均取款额度超出存储金额时,Hogg由于具有透支权限,才得以成功完成操作。注意之后创建的两个对象dom和dot,从调用ViewAcct()函数过程中再次体会虚函数的意义。若没有使用virtual关键字,程序根据引用或指针的类型选择使用基类方法还是派生类同名的重载后方法。若使用该关键字,则根据引用或指针所指向对象的类型来选择。程序中,b1_ref和b2_ref均是Brass类引用,但分别是Brass类对象dom和BrassPlus类对象dot的别名,因此使用virtual关键字后的ViewAcct()函数,依次调用基类和派生类方法.
以上所述是小编给大家介绍的C++基础——类继承中方法重载详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我网站的支持! 。
最后此篇关于详解C++基础——类继承中方法重载的文章就讲到这里了,如果你想了解更多关于详解C++基础——类继承中方法重载的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我想了解 Ruby 方法 methods() 是如何工作的。 我尝试使用“ruby 方法”在 Google 上搜索,但这不是我需要的。 我也看过 ruby-doc.org,但我没有找到这种方法。
Test 方法 对指定的字符串执行一个正则表达式搜索,并返回一个 Boolean 值指示是否找到匹配的模式。 object.Test(string) 参数 object 必选项。总是一个
Replace 方法 替换在正则表达式查找中找到的文本。 object.Replace(string1, string2) 参数 object 必选项。总是一个 RegExp 对象的名称。
Raise 方法 生成运行时错误 object.Raise(number, source, description, helpfile, helpcontext) 参数 object 应为
Execute 方法 对指定的字符串执行正则表达式搜索。 object.Execute(string) 参数 object 必选项。总是一个 RegExp 对象的名称。 string
Clear 方法 清除 Err 对象的所有属性设置。 object.Clear object 应为 Err 对象的名称。 说明 在错误处理后,使用 Clear 显式地清除 Err 对象。此
CopyFile 方法 将一个或多个文件从某位置复制到另一位置。 object.CopyFile source, destination[, overwrite] 参数 object 必选
Copy 方法 将指定的文件或文件夹从某位置复制到另一位置。 object.Copy destination[, overwrite] 参数 object 必选项。应为 File 或 F
Close 方法 关闭打开的 TextStream 文件。 object.Close object 应为 TextStream 对象的名称。 说明 下面例子举例说明如何使用 Close 方
BuildPath 方法 向现有路径后添加名称。 object.BuildPath(path, name) 参数 object 必选项。应为 FileSystemObject 对象的名称
GetFolder 方法 返回与指定的路径中某文件夹相应的 Folder 对象。 object.GetFolder(folderspec) 参数 object 必选项。应为 FileSy
GetFileName 方法 返回指定路径(不是指定驱动器路径部分)的最后一个文件或文件夹。 object.GetFileName(pathspec) 参数 object 必选项。应为
GetFile 方法 返回与指定路径中某文件相应的 File 对象。 object.GetFile(filespec) 参数 object 必选项。应为 FileSystemObject
GetExtensionName 方法 返回字符串,该字符串包含路径最后一个组成部分的扩展名。 object.GetExtensionName(path) 参数 object 必选项。应
GetDriveName 方法 返回包含指定路径中驱动器名的字符串。 object.GetDriveName(path) 参数 object 必选项。应为 FileSystemObjec
GetDrive 方法 返回与指定的路径中驱动器相对应的 Drive 对象。 object.GetDrive drivespec 参数 object 必选项。应为 FileSystemO
GetBaseName 方法 返回字符串,其中包含文件的基本名 (不带扩展名), 或者提供的路径说明中的文件夹。 object.GetBaseName(path) 参数 object 必
GetAbsolutePathName 方法 从提供的指定路径中返回完整且含义明确的路径。 object.GetAbsolutePathName(pathspec) 参数 object
FolderExists 方法 如果指定的文件夹存在,则返回 True;否则返回 False。 object.FolderExists(folderspec) 参数 object 必选项
FileExists 方法 如果指定的文件存在返回 True;否则返回 False。 object.FileExists(filespec) 参数 object 必选项。应为 FileS
我是一名优秀的程序员,十分优秀!