继承实例(进制转换)

来源:互联网 发布:淘宝网卧室台灯 编辑:程序博客网 时间:2024/06/05 18:28

定义一个任意进制的数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类的成员方法。应该用类的组合来实现。

原创粉丝点击