1-04 C++起步: 数据与代码的集成 —— C++对结构的扩充
来源:互联网 发布:化工仿真软件步骤 编辑:程序博客网 时间:2024/05/01 14:56
在C语言里, 结构里只能包含数据成员, 例如下面的时钟类型:
struct TIME {
int hour, minute, second;
};
然后, 我们可以设计的一系列与之有关的函数。包括: 设置、输入、输出等, 使其用起来非常方便, 例如:
int main() {
TIME a, b; // 定义时钟a和b
Set(a, 12, 30, 15); // a设置成12:30:15
Output(a); // 输出a, 格式为"12:30:15"
cout << "请输入时间: ";
Input(b); // 输入b
Output(b); // 输出b
return 0;
}
首先编写输出函数, 它最简单:
void Output(const TIME &t) {
cout << t.hour << ':' << t.minute << ':' << t.second << endl;
}
然后编写设置函数, 显然, 该函数应该对所给出的参数进行判断, 如果参数正确, 则进行设置操作, 否则, 就报告错误:
void Set(TIME &t, int h, int m, int s) {
if (h>=0 && h<24 && m>=0 && m<60 && s>=0 && s<60) {
t.hour = h; t.minute = m; t.second = s;
}
else cerr << "不正确的时钟数据: " << h << ", " << m << ", " << s << "/a/n";
}
最后编写输入函数, 同样, 它也要判断用户从键盘输入的数据是否正确, 若用户输入的数据无效, 则要求重新输入:
void Input(TIME &t) {
int h, m, s;
while (cin >> h >> m >> s, h<0 || h>=24 || m<0 || m>=60 || s<0 || s>=60) {
cout << "不正确的时钟数据: " << h << ", " << m << ", " << s << "/a/n请重新输入: ";
}
t.hour = h; t.minute = m; t.second = s;
}
等程序编到这里, 我们才发现, 对时钟数据的有效性判断是一个多次用到的功能, 所以它应该写成一个函数。这个函数的参数是时、分、秒, 函数值是逻辑值, 如果数据有效, 则函数返回真值, 否则为假值:
bool IsTime(int h, int m, int s) {
if (h>=0 && h<24 && m>=0 && m<60 && s>=0 && s<60)
return true;
else
return false;
}
初学者的经常写出这样的代码, 这说明他对关系运算和逻辑类型的理解尚不透彻。下面的推荐的写法:
bool IsTime(int h, int m, int s) {
return h>=0 && h<24 && m>=0 && m<60 && s>=0 && s<60;
}
这里, 关系表达式(h>=0 && h<24 && m>=0 && m<60 && s>=0 && s<60)的值是一个逻辑值, 不是true, 就是false, 根本不需要写什么if语句。
有了这个判断时钟数据有效性的函数, 我们可以改写设置函数和输入函数, 使其更简洁、明了:
void Set(TIME &t, int h, int m, int s) {
if (IsTime(h, m, s)) {
t.hour = h; t.minute = m; t.second = s;
}
else cerr << "不正确的时钟数据/n";
}
若 h, m, s 是有效的时钟数据, 则设置时钟; 否则显示错误信息。
void Input(TIME &t) {
int h, m, s;
while (cin >> h >> m >> s, !IsTime(h, m, s)) {
cout << "不正确的时钟数据/n请重新输入: ";
}
t.hour = h; t.minute = m; t.second = s;
}
若用户输入的 h, m, s 不是有效的时钟数据, 则通过循环, 要求用户重新输入; 若数据有效则结束循环, 然后设置时钟。
下面是完整的程序:
TIME.H
#ifndef _TIME_H_
#define _TIME_H_
struct TIME {
int hour, minute, second;
};
bool IsTime(int h, int m, int s);
void Set(TIME &t, int h, int m, int s);
void Input(TIME &t);
void Output(const TIME &t);
#endif
TIME.CPP
#include <iostream>
using namespace std;
#include "time.h"
bool IsTime(int h, int m, int s) {
return h>=0 && h<24 && m>=0 && m<60 && s>=0 && s<60;
}
void Set(TIME &t, int h, int m, int s) {
if (IsTime(h, m, s)) {
t.hour = h; t.minute = m; t.second = s;
}
else cerr << "不正确的时钟数据: " << h << ", " << m << ", " << s << "/a/n";
}
void Input(TIME &t) {
int h, m, s;
while (cin >> h >> m >> s, !IsTime(h, m, s)) {
cout << "不正确的时钟数据: " << h << ", " << m << ", " << s << "/a/n请重新输入: ";
}
t.hour = h; t.minute = m; t.second = s;
}
void Output(const TIME &t) {
cout << t.hour << ':' << t.minute << ':' << t.second << endl;
}
MAIN.CPP
#include <iostream>
using namespace std;
#include "time.h"
int main() {
TIME a, b;
Set(a, 12, 30, 15); // 数据正确
Output(a);
Set(a, 200, -45, 95); // 数据错误
Output(a);
cout << "请输入时间: ";
Input(b);
Output(b);
return 0;
}
程序运行结果如下, 其中用户第一次输入的数据是: 25时30分88秒, 第二次重新输入的数据是: 23时59分58秒:
12:30:15
不正确的时钟数据: 200, -45, 95
12:30:15
请输入时间: 25 30 88
不正确的时钟数据: 25, 30, 88
请重新输入: 23 59 58
23:59:58
在上面的例子以及1-03的例子里面, 在结构中只定义了数据成员, 而函数都是独立于结构之外的全局函数, 即从语言的角度来看, 函数与结构并无内在联系; 然而, 从问题本身来看, 显然这一组函数与结构有着密切的联系, 它们本应该是一个不可分割的整体, 只是因为C语言的表达能力有限, 使它们看起来互不相干。
C++对C的结构进行了扩充, 允许在结构里定义数据成员和成员函数, 实现了数据和函数的初步集成, 它们形成了一个完整的整体:
struct TIME {
int hour, minute, second;
bool IsTime(int h, int m, int s);
void Set(int h, int m, int s);
void Input();
void Output();
};
成员函数与普通函数不同, 它们的使用的方法发生了变化:
int main() {
TIME a, b;
a.Set(12, 30, 15); // 对a发消息, 令其变为12:30:15
a.Output(); // 对a发消息, 令其输出内容
cout << "请输入时间: ";
b.Input(); // 对b发消息, 令其从键盘输入新内容
b.Output(); // 对b发消息, 令其输出内容
return 0;
}
这正是面向对象程序的特点, 程序是由对象和向对象发出的消息组成。即:
程序 = 对象 + 消息
面向过程的程序
(普通函数)
面向对象的程序
(成员函数)
Set(a, 12, 30, 15);
Input(a);
Output(a);
a.Set(12, 30, 15);
a.Input();
a.Output();
在面向过程的程序里, 以功能为核心。语句是Input(a), 即:
- 您要做什么?
- 输入数据!
- 保存到哪里?
- 变量a中!
在面向对象的程序里, 以对象为核心。语句是a.Input(), 即:
- 您要找谁?
- 找对象a!
- 要它做什么?
- 输入数据!
用录音机做比喻。在面向过程的程序里, 我们首先要决定做什么操作, 如录音、放音、快进或快退等, 然后再看把操作施回到哪一台录音机上; 而在面向对象的程序里, 录音机是一个对象, 我们首先确定用哪一台录音机, 然后向该录音机发出操作指令, 录音机似乎是一台智能设备, 能自动响应我们的要求。
定义在结构中的函数称为成员函数, 为了与普通函数以示区别, 定义它们时, 成员函数名前要冠以类的名称, 并以作用域运算符“::”隔开。例如:
bool TIME::IsTime(int h, int m, int s) {
return h>=0 && h<24 && m>=0 && m<60 && s>=0 && s<60;
}
用下面的方法写出的函数, 不是成员函数, 它不属于任何类, 是一个“独立”的函数:
bool IsTime(int h, int m, int s) {
return h>=0 && h<24 && m>=0 && m<60 && s>=0 && s<60;
}
下面是完整的程序:
TIME.H
#ifndef _TIME_H_
#define _TIME_H_
struct TIME {
int hour, minute, second;
bool IsTime(int h, int m, int s);
void Set(int h, int m, int s);
void Input();
void Output() const;
};
#endif
TIME.CPP
#include <iostream>
using namespace std;
#include "time.h"
bool TIME::IsTime(int h, int m, int s) {
return h>=0 && h<24 && m>=0 && m<60 && s>=0 && s<60;
}
void TIME::Set(int h, int m, int s) {
if (IsTime(h, m, s)) {
hour = h; minute = m; second = s;
}
else cerr << "不正确的时钟数据: " << h << ", " << m << ", " << s << "/a/n";
}
void TIME::Input() {
int h, m, s;
while (cin >> h >> m >> s, !IsTime(h, m, s)) {
cout << "不正确的时钟数据: " << h << ", " << m << ", " << s << "/a/n请重新输入: ";
}
hour = h; minute = m; second = s;
}
void TIME::Output() const {
cout << hour << ':' << minute << ':' << second << endl;
}
MAIN.CPP
#include <iostream>
using namespace std;
#include "time.h"
int main() {
TIME a, b;
a.Set(12, 30, 15); // 数据正确
a.Output();
a.Set(200, -45, 95); // 数据错误
a.Output();
cout << "请输入时间: ";
b.Input();
b.Output();
return 0;
}
程序运行结果如下, 其中用户第一次输入的数据是: 25时30分88秒, 第二次重新输入的数据是: 23时59分58秒:
12:30:15
不正确的时钟数据: 200, -45, 95
12:30:15
请输入时间: 25 30 88
不正确的时钟数据: 25, 30, 88
请重新输入: 23 59 58
23:59:58
这个版本已经与C++的类非常接近了, 只是结构中的成员默认的访问属性公有的。公有的成员, 在类任何地方都可以访问, 因此, 用户以下面的几种方式来访问结构, 都是合法的:
通过成员函数访问
直接操纵数据成员
a.Set(12, 30, 15);
a.hour = 12;
a.minute = 30;
a.second = 15;
a.Input();
cin >> a.hour >> a.minute >> a.second;
a.Output();
cout << a.hour << ':' << a.minute << ':' << a.second << endl;
显然, 结构虽然提供了将数据成员和成员函数集成到一起的手段, 但所有成员都是公有的, 所以它不安全。用户设置时钟, 如果通过成员函数来设置, 由于设置函数具有判断功能, 不会允许错误的数据; 如果用户不通过成员函数设置, 直接操纵数据成员, 那么这个程序就无能为力了, 比如用户可以作以下错误设置:
a.hour = 200; a.minute = -45; a.second = 95;
要解决这个问题, 需要使用C++面向对象程序设计的新工具 —— 类。
- 1-04 C++起步: 数据与代码的集成 —— C++对结构的扩充
- 1-05 C++起步: 结构与联合 —— C++对联合的扩充
- C++对C的扩充(1)
- C++对C的扩充
- C++对C的扩充
- C++对C的扩充
- C++对C的扩充
- C++中对C语言结构体用法的扩充
- C++对C的扩充(2)
- C++对C语言的扩充之一
- C++语言对C语言的扩充
- 第二讲:C++对C的扩充(1)
- 第七天2017/04/14(C++对C的扩充,C++与C的区别,C++的基础知识)
- 《C++程序设计教程》——C++对C语言的扩充
- 36、C++对C语言的面向对象的扩充
- 第三讲:C++对C的扩充(2)
- C语言的负数扩充
- C++对C语言的非面向对象特性扩充(1)-- 注释、输入输出、局部变量说明、C++中const修饰符与C中的#define
- 我的心你不要忧郁 德.海涅
- 抽象工厂设计模式
- 爱的表达
- 交换提单SWITCH B/L
- 看书+思考=智慧
- 1-04 C++起步: 数据与代码的集成 —— C++对结构的扩充
- 【一棵开花的树】 席慕容
- 为treeview添加客户端事件
- 用asp实现base64编码
- asp彩色验证码图像生成脚本
- ASP.NET 开发人员应当始终坚持的做法
- 连接各种数据库写法
- 给技术人员的一些忠告
- 嵌入式系统与嵌入式操作系统