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

上篇我们讲了类设计的5大步骤,那么这次我们就来用实际例子来实现这5大步骤。

采用用户的视角(Adopting the client perspective)

作为Rational类设计的第一步,你需要考虑客户可能需要哪些功能。在一家大型公司中,您可能会有各种实施团队需要使用合理的数字,并且可以很好地了解他们需要什么。在这种情况下,与这些客户合作并达成一致的设计目标通常很有用。
鉴于我们这里没有具体的客户,我们假设客户希望我们实现下图的功能:

对应的是我们分数的加减乘除。

Rational类的私有部分

对于Rational类,私有状态很容易指定。有理数被定义为两个整数的商。因此,每个有理数对象必须由这两个整数产生。 因此,将进入私有部分的实例变量的声明为:

int num;
int den;

这些变量的名称是数学术语分子(numerator)和分母(denominator)的缩写版本,它们是指分数的上部和下部。

Rational类的构造函数

假定一个有理数字代表两个整数的商,其中一个构造函数可能假定代表分数中的两个整数。有了这样一个构造函数就可以通过调用Rational(1,3)来定义理性数字三分之一(1/3)。构造函数的这种形式的原型如下所示:

Rational(int x, int y);

虽然在这个阶段没有必要考虑怎么去实现这个功能,但在你的头脑中一直在考虑怎么实现问题有时可以让你头痛。 在这种情况下,值得一提的是,以下列形式实现此构造方法是不合适的:

Rational(int x, int y) {
    num = x;
    den = y;
}

这个实现的问题是位置约束对分子和分母约束的值需要考虑进去构造函数中。最明显的约束是分母的值不能为零,并且构造函数应该检查这种情况,并发出错误信号。 然而,这是一个更微妙的问题。如果客户被给予分子和分母的不受约束的选择,则将有许多不同的方式来表示相同的有理数字。 例如,有理数三分之一可以用以下写成下列的任一种形式:

假设这些分数都表示相同的有理数,那么我们应该将其视为不合法的并不允许在Rational对象中允许使用分子和分母值的任意组合。如果每个合理的数字都具有一致,独特的表示,它将大大简化我们的实现。
数学家们通过以下规则实现这一目标:

  • 分数总是以最低的值表示(即最简方式),这意味着任何常见因素都从分子和分母中消除。在实践中,将分数减少到最低项的最简单方法是将分子和分母除以最大公约数,我们用gcd函数来计算。
  • 分母总是为正,这意味着该值的符号与分子一起存储。
  • 有理数0始终表示为0/1的分数。

所以我们可以用下面的代码来实现构造函数:

Rational(int x, int y) {
    if (y == 0) error("Rational: Division by zero");
    if (x == 0) {
    num = 0;
    den = 1;
    } else {
        int g = gcd(abs(x), abs(y));//abs函数为取绝对值
        num = x / g;
        den = abs(y) / g;
        if (y < 0) num = -num;
    }
}

作为一般规则,每个类都应该有一个默认构造函数,当声明中没有提供任何参数时,该构造函数将被使用。默认有理数的适当数学值为零,表示为分数0/1。因此,默认构造函数的代码看起来像这样;

Rational() {
    num = 0;
    den = 1;
}

最后,最终定义构造函数的第三个版本是有用的,它接受一个表示整数的参数:

Rational(int n) {
    num = n;
    den = 1;
}

为Rational类定义方法

鉴于之前我们将Rational类的功能限于算术运算符的决定,找出导出的方法是一个比较容易的任务,特别是在C++中。在许多面向对象的语言(包括Java)中,例如,定义算术运算的唯一方法是导出名为add,subtract,multiply和divide的方法来实现四个算术运算。更糟糕的是,您必须使用接收器语法来应用这些运算符。而不是写令人满意的声明。

Rational sum = a + b + c;

这句话在java中你得这样写:

Rational sum = a.add(b).add(c);

虽然解决这个表达意味着什么并不困难,但是对比C++它在重新定义算术运算符上却没有强大的灵活性和表达力。
在C++中情况好多了。 在C++中,通过重载运算符+, - ,*和/来处理Rational对象来实现有理数的运算。正如的Point类一样,将这些运算符定义为自由函数比方法更容易,这意味着四个运算符的原型如下所示:

Rational operator+(Rational r1, Rational r2);
Rational operator-(Rational r1, Rational r2);
Rational operator*(Rational r1, Rational r2);
Rational operator/(Rational r1, Rational r2);

与Point类中的==运算符一样,这些算术运算符将需要访问r1和r2的字段,这意味着这些操作符方法必须声明为Rational类的朋友。 放置这些声明的最方便的地方在rationalpriv.h文件中,隐藏在该类的私有部分。
尽管在Rational类的专业实现中还有许多其他方法和操作符是有意义的,但本示例中包含的唯一附加功能是一个toString方法和<<操作符的重载版本,主要是为了让你习惯 将这些设施纳入你设计的每个类中。能够以人类可读的形式显示对象的值对于测试和调试非常重要,这是开发过程的重要阶段。

实现Rational类

接下来的代码我就在下一篇博客贴出来,老规矩。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
8.17 (Rational Numbers) Create a class called Rational for performing arithmetic with fractions. Write a program to test your class. Use integer variables to represent the private instance variables of the class the numerator and the denominator. Provide a constructor that enables an object of this class to be initialized when it is declared. The constructor should store the fraction in reduced form. The fraction 2/4 is equivalent to 1/2 and would be stored in the object as 1 in the numerator and 2 in the denominator. Provide a no-argument constructor with default values in case no initializers are provided. Provide public methods that perform each of the following operations: a. Add two Rational numbers: The result of the addition should be stored in reduced form. b. Subtract two Rational numbers: The result of the subtraction should be stored in reduced form. c. Multiply two Rational numbers: The result of the multiplication should be stored in reduced form. d. Divide two Rational numbers: The result of the division should be stored in reduced form. e. Print Rational numbers in the form a/b, where a is the numerator and b is the denominator. f. Print Rational numbers in floating-point format. (Consider providing formatting capabilities that enable the user of the class to specify the number of digits of precision to the right of the decimal point.) – 提示: – 有理数是有分子、分母以形式a/b表示的数,其中a是分子,b是分母。例如,1/3,3/4,10/4。 – 有理数的分母不能为0,分子却可以为0。每个整数a等价于有理数a/1。有理数用于分数的精确计算中。例如1/3=0.0000…,它不能使用数据型double或float的浮点格式精确表示出来,为了得到准确结果,必须使用有理数。 – Java提供了整数和浮点数的数据型,但是没有提供有理数的型。 – 由于有理数与整数、浮点数有许多共同特征,并且Number是数字包装的根,因此,把有理数Rational定义为Number的一个子是比较合适的。由于有理数是可比较的,那么Rational也应该实现Comparable接口。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值