继承实例(进制转换)

定义一个任意进制的数Number类,继承自string类:

Number类的数据成员:
_radix表示数的基数,
_inum表示数的相应的十进制数

用string存储任意进制的数(可以说是用字符串来存,r进制的数不适合用int来存)

/*
Number类的数据成员:
_radix表示数的基数,
_inum表示数的相应的十进制数
*/
// more: http://msdn.microsoft.com/en-us/library/0heszx3w.aspx

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

class Number : public string {
public:
	Number(string str = "", unsigned int radix = 0, int inum = 0)
		: string(str), _radix(radix) ,_inum(inum) {}
	void set(unsigned int radix);
	void strtoi(void);
	void itostr(void);
	Number operator+(const Number &);

private:
	unsigned int _radix;
	int _inum;	// 该数的十进制表示
};

void Number::set(unsigned int radix)
{
	_radix = radix;
	strtoi();
	// 字符串一但改变,_inum马上变,与+无关
	// 哪个属性更新了,就马上调用相应的方法以随时保持一致
}

void Number::itostr(void)	// 十进制到r进制:除k取余法
{
	Number &str = *this;

	if(_inum == 0) {
		str.push_back('0');
	}
	else {
		int balance = 0;
		for(int i = 0; _inum > 0; i++) {
			balance = _inum % _radix;
			// 注意十六进制
			str.push_back(balance + (balance < 10 ? '0' : 'A' - 10));
			_inum /= _radix;
		}
		reverse(str.begin(), str.end());
	}
}

void Number::strtoi(void)	// r进制到十进制:秦九韶算法
{
	const Number &str = *this;
	if ('0' <= str[0] && str[0] <= (min((int)'9', (int)('0' + _radix - 1))))
		_inum = str[0] - '0';
	else if ('A' <= str[0] && str[0] <= 'Z')	// 注意十六进制,以下待合法性检查
		_inum = 10 + str[0] - 'A';
	else {
		cout << "Input Error!" << endl;
		return ;
	}  // 秦九韶算法中的第一个数

	for (unsigned int i = 1; i < str.length(); i++) {
		if ('0' <= str[i] && str[i] <= '9')
			_inum = (_inum * _radix) + str[i] - '0';
		else if ('A' <= str[i] && str[i] <= 'Z')
			_inum = (_inum * _radix) + 10 + str[i] - 'A';
		else {
			cout << "Input Error!" << endl;
			return ;
		}
	}
}

Number Number::operator+(const Number &b)
{
	Number sum;
	Number &a = *this;
	if(a._radix != b._radix) {
		cerr << "a与b的基数不相等!" << endl;
		exit(-1);
	}
	sum._radix = a._radix;
	sum._inum = a._inum + b._inum;
	sum.itostr();	// 紧跟_inum的变化调用
	return sum;
	//	return IToA(AToI(a) + AToI(b), a.radix());
}

int main(void)
{
	Number a, b;
	int radix;
	while (cin >> radix && radix >= 2) {
		cin >> a >> b;
		// set前必须输入a与b,要初始化(见set函数),这同时也是一个缺陷,待改进
		a.set(radix);
		b.set(radix);	//  这两句最好到构造函数中去(封装起来?),待改进
		Number c = a + b;
		cout << a << " + " << b << " = " << c << endl << endl;
	}

	return 0;
}

运行结果如下(依次输入基数,第一个数,第二个数):

为什么说继承方便呢?你是否注意到输入a,b时竟然可以直接cin,cout,在itostr函数中用了push_back等string类的成员函数,及在strtoi函数中也用了[ ]运算符,这些其实都是string类中的成员函数(包括标准输入输出的>>与<<),Number类公有继承了string类,都可以直接拿来用了,挺方便!

这里的Number类中只重载了+,当然可以类比地重载-, *, /,这里我就不多写了。

其实在此之前我写了几个版本,比如没使用_inum作为数的属性,重载+、进制转换函数是作为全局函数的。而现在写的版本基本符合一个封装了。

启示:为什么定义类时往往不把属性设为公有的,其中的原因是为了安全性。而我从这篇博客得到了另一点原因,在继承时也使结构更清晰(猜想),我对C++的string类的内部也不是很了解,看源码没找到string类的数据成员,其实string类也是从其它类继承来的。

附:之前的一个版本

// 进制互转运算,十进制数用int表示,其他进制数用Number表示
// http://msdn.microsoft.com/en-us/library/0heszx3w.aspx
#include <iostream>
#include <string>
#include <cassert>
#include <algorithm>
using namespace std;

class Number : public string {
	unsigned int _radix;

public:
	Number(string str = "", int r = 0) : string(str), _radix(r) {}
	Number operator+(const Number &);
	Number operator-(const Number &);
	Number operator*(const Number &);
	Number operator/(const Number &);
	void set(unsigned int r) {
		_radix = r;
	}
	unsigned int radix(void) const {
		return _radix;
	}
};

Number IToA(int inum, int radix);	// 必须在这声明
int AToI(Number str);

Number Number::operator+(const Number &b)
{
	const Number &a = *this;	
	assert(a.radix() == b.radix());

	return IToA(AToI(a) + AToI(b), a.radix());
}

Number Number::operator-(const Number &b)
{
	const Number &a = *this;	
	assert(a.radix() == b.radix());

	return IToA(AToI(a) - AToI(b), a.radix());
}

Number Number::operator*(const Number &b)
{
	const Number &a = *this;	
	assert(a.radix() == b.radix());

	return IToA(AToI(a) * AToI(b), a.radix());
}

Number Number::operator/(const Number &b)
{
	const Number &a = *this;	
	assert(a.radix() == b.radix());

	return IToA(AToI(a) / AToI(b), a.radix());
}

Number IToA(int inum, int radix)
{
	Number str;

	if(inum == 0) {
		str.push_back('0');
	}
	else {
		int balance = 0;
		for(int i = 0; inum > 0; i++) {
			balance = inum % radix;
			str.push_back(balance + (balance < 10 ? '0' : 'A' - 10));
			inum /= radix;
		}
		reverse(str.begin(), str.end());
	}

	return str;
}

int AToI(Number str)
{
	int inum = (str[0] < 'A' ? str[0] - '0' : 10 + str[0] - 'A');	// 可加强检查合法性
	for (unsigned int i = 1; i < str.length(); i++) {
		inum = (inum * str.radix()) + (str[i] < 'A' ? str[i] - '0' : 10 + str[i] - 'A');
	}

	return inum;
}
/*
// 早期版本
Number operator*(Number a, Number b)
{
	assert(a.radix() == b.radix());

	return IToA(AToI(a) * AToI(b), a.radix());
}
*/
int main(void)
{
	Number a, b;
	int radix;
	while (cin >> a >> b >> radix) {
		assert(radix >= 2);
		a.set(radix);
		b.set(radix);
		cout << a << " + " << b << " = " << a + b << endl
			<< a << " - " << b << " = " << a - b << endl
			<< a << " * " << b << " = " << a * b << endl
			<< a << " / " << b << " = " << a / b << endl << endl;
	}

	return 0;
}

2012/7/29

其实关于r进制的那些字符(0123456789ABCDEF)用个哈希挺不错(参考自:http://www.cnblogs.com/applebunny/archive/2012/06/21/2557361.html):

const char a[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

避免繁杂的ANSII码计算


2013/4/5

现在看这篇博客,其实设计是不对的,string类和Number类不是继承关系,原来只是为了方便而借用了string类的成员方法。

新的设计参见:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值