C++抽象编程——面向对象(6)——设计新的类(1)

虽然前面我们定义中的Point类说明了用于定义新类的基本机制,但对于面向对象的理解需要考虑更复杂的示例。所以接下来我们就以一个实例来设计一个有理数的类别,它也可以表示两个数的相除,或者我们可以称他们为分数。接下来我们一步一步的实现它。(所以下面的有理数指的是分数)

有理数与浮点数

在某些方面,有理数(Rational numbers)与我们以前一直使用的浮点数相似。两种类型的数字都可以表示分数值,如1.5,这是有理数3/2。不同之处在于,有理数是精确的,而浮点数则受到硬件精度的限制。
要了解为什么这种区别很重要,请考虑将以下分数相加的算术问题:

显然的是,数学上精确的答案是1,但是这个答案是不可能在计算机上使用双精度算术获得的。我们可以编写程序执行此计算并显示16位结果:

#include <iostream>
#include <iomanip> //setprecision
using namespace std;
int main() {
    double a = 1.0 / 2.0;
    double b = 1.0 / 3.0;
    double c = 1.0 / 6.0;
    double sum = a + b + c;
    cout << setprecision(16);//控制输出流显示浮点数的有效数字个数
    cout << "1/2 + 1/3 + 1/6 = " << sum << endl;
    cout << a << endl;
    cout << b << endl;
    cout << c << endl;
    return 0;
}

运行结果是:

我们可以看到,虽然最后结果是1,但是这个1的前提是c的值进行了四舍五入的,不然它的值是0.16666666……,因此,从double类型的角度看,如果不四舍五入,那么结果就是这样的:

问题在于,用于在计算机内存储数字的存储单元具有有限的存储容量,这反过来又限制了它们可以提供的精度。在双精度算术的限度内,加上一半加三分之一加 六分之一更接近0.9999999999999999,而不是1.0。 更糟糕的是,这个总和的计算值真的小于1,如果你要在你的程序中测试,就会显示出来。 在运行结束时,表达式sum <1的值将为真,并且sum == 1的值将为false。 从数学的角度来看,这一结果显然是不应该的。
合理的数字不会受到舍入误差的影响(比如1/2 = 0.5),因为不涉及近似值。 此外,有理数能被很好地理解为具有自己的算术规则的数学概念,问题是C++不包括其预定义类型中的有理数字。 要在C++中使用有理数字,您必须定义一个新类来表示它们。

怎么设计一个新的类?

当你以面向对象语言工作时,设计新的类是你需要掌握的最重要的技能。与大多数编程一样,设计一个新类就像一门科学一样的艺术。开发有效的新的类的设计需要强烈的美学意识和对使用这些类作为工具的客户的需求要相当敏感。经验和实践是最好的老师,但遵循一般的设计框架可以帮助你沿着这条路开始。
一般来说我们可以通过下面的步骤来设计一个新的类:
1. 在客户的角度考虑,客户端可能会如何使用该类Think generally about how clients are likely to use the class.)。从进程的一开始,必须记住,库类的设计是为了满足客户的需求而不是为了方便实现者。在专业环境中,确保新的类满足这些需求的最有效方法是让客户参与设计过程。至少在您绘制类设计的轮廓时,您需要将自己置于客户角色中。
2. 确定哪些信息应该是对象的私有成员Determine what information belongs in the private state of each object.)。 虽然私有部分在概念上是实现类的一部分,但是如果你至少知道这个对象应该包含那些信息,这将大大简化后期的设计阶段。在许多情况下,你可以将实例变量写入到私有部分。尽管在这一点上这个精确的细节并不是必要的,但对内部结构的有一定的了解可以使得它更容易定义其构造函数和方法。
3. 定义一组构造函数来创建新对象Define a set of constructors to create new objects)。 类通常定义了多个构造函数的重载形式,从客户端的角度来看,我们通常从需要创建的对象的类型以及客户端在当时的手头信息来思考。通常,每个类都导出一个默认构造函数,这使得客户端可以声明该类的变量并稍后对其进行初始化。在此阶段,考虑构造函数是否需要应用任何限制以确保生成的对象是有效的也是有用的。
4. 罗列将成为该类的公共方法及其操作。在这个阶段,目标是为出口的方法编写原型,从而为你在开始时开发的一般大纲增加了特殊性。你也可以使用此阶段来完善整体设计,遵循我们之前在接口概述的统一性,简单性,充分性,一般性和稳定性原则。(其实就是编写方法的原型)
5. 编码和并测试其实现。(Code and test the implementation) 一旦你有了接口规范,你就需要编写实现它的代码。编写实现当然是必要的工作程序,但也提供验证的设计。在编写实现时,有时需要重新访问接口设计,例如,如果您发现特定功能难以在可接受的效率水平上实现。作为实现者,您还有责任测试类,以确保该类在接口中发布的功能可以实现的。

介绍了基本的步骤,下一篇我们就以有理数类的设计,一步一步体现上面的5个步骤是怎么设计并实现一个类的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
面向对象编程中,C语言并不直接支持抽象的概念。引用中提到,final关键字用来修饰方法,表示该方法不能在子中被覆盖。而abstract关键字用来修饰抽象方法,表示该方法必须在子中被实现。然而,在C语言中,没有对应的关键字来实现抽象的概念。 相反,C语言通过结构体来模拟的概念。结构体是一种用户自定义的数据型,可以包含多个不同型的数据成员。通过结构体,我们可以将相关的数据和功能组合在一起。然而,C语言中的结构体不支持继承和多态等面向对象的特性。 在C语言中,我们可以使用函数指针来模拟抽象和接口的概念。函数指针可以指向不同的函数,通过使用函数指针,我们可以实现多态性,即在运行时根据函数指针指向的具体函数来执行不同的操作。 综上所述,C语言并不直接支持面向对象中的抽象的概念,但可以使用结构体和函数指针来实现似的功能。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [面向对象——和对象](https://blog.csdn.net/shouyeren_st/article/details/126210622)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [面向对象编程原则(06)——依赖倒转原则](https://blog.csdn.net/lfdfhl/article/details/126673771)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值