前言
本周老师布置了一道编程题目,让我们实现大整数的加法和乘法。刚好我太久没接触编程,正好用这道题练练手,我也明白在本学期算法会是一个关键难点,而我在这个方面也差的太远,而且类的使用也不大熟练(倒不是难,理解清楚一些基本的算法其实是不难的,主要还是因为我懒)
一、c++中的类
这里用到的知识点主要是类成员的访问和运算符重载。这里我把在菜鸟教程上的知识做一个摘录。同时也把我觉得有点陌生的友元函数,多态做一个笔记。
为什么要用类来实现
运算符重载后实现起来看着很美观,有一种雅致和简约的美。
类的定义
定义一个类,本质上是定义一个数据类型的蓝图。这实际上并没有定义任何数据,但它定义了类的名称意味着什么,也就是说,它定义了类的对象包括了什么,以及可以在这个对象上执行哪些操作。
类的继承
一个类可以派生自多个类,这意味着,它可以从多个基类继承数据和函数。定义一个派生类,我们使用一个类派生列表来指定基类。类派生列表以一个或多个基类命名,形式如下:
class derived-class: access-specifier base-class
派生类可以访问基类中所有的非私有成员。因此基类成员如果不想被派生类的成员函数访问,则应在基类中声明为 private。
我们可以根据访问权限总结出不同的访问类型,如下所示:
访问 | public | protected | private |
---|---|---|---|
同一个类 | yes | yes | yes |
派生类 | yes | yes | no |
外部的类 | yes | no | no |
(这个表格的制作花了不少时间,实际上可以很简单就画出来,害)
- 公有继承(public):当一个类派生自公有基类时,基类的公有成员也是派生类的公有成员,基类的保护成员也是派生类的保护成员,基类的私有成员不能直接被派生类访问,但是可以通过调用基类的公有和保护成员来访问。
- 保护继承(protected): 当一个类派生自保护基类时,基类的公有和保护成员将成为派生类的保护成员。
- 私有继承(private):当一个类派生自私有基类时,基类的公有和保护成员将成为派生类的私有成员。
类的友元函数和友元类
类的友元函数是定义在类外部,但有权访问类的所有私有(private)成员和保护(protected)成员。尽管友元函数的原型有在类的定义中出现过,但是友元函数并不是成员函数。
友元可以是一个函数,该函数被称为友元函数;友元也可以是一个类,该类被称为友元类,在这种情况下,整个类及其所有成员都是友元。
如果要声明函数为一个类的友元,需要在类定义中该函数原型前使用关键字 friend,如下所示:
class Box
{
double width;
public:
double length;
friend void printWidth( Box box );
void setWidth( double wid );
};
因为友元函数没有this指针,则参数要有三种情况:
- 要访问非static成员时,需要对象做参数;
- 要访问static成员或全局变量时,则不需要对象做参数;
- 如果做参数的对象是全局对象,则不需要对象做参数.
可以直接调用友元函数,不需要通过对象或指针
多态
to be continued 这个相对来说复杂一点,以后如果有空再补
运算符重载
您可以重定义或重载大部分 C++ 内置的运算符。这样,您就能使用自定义类型的运算符。
重载的运算符是带有特殊名称的函数,函数名是由关键字 operator 和其后要重载的运算符符号构成的。与其他函数一样,重载运算符有一个返回类型和一个参数列表。
Box operator+(const Box&);
二、代码解释
数据解释
class number
{
private:
int *value;
int length;
public:
void show_value() //展示数据的结果
{
for(int i = 0;i < this->length;i++) cout<<*(this->value+i);
cout<<endl;
}
number operator+(number a) //加法核心
{
//为了展示放在后面
}
void set_value(int *b) //用来初始化值的,现在想想看用构造函数可能要方便些
{
this->value = b;
}
void set_length(int d)
{
this->length = d;
}
number operator*(number c)
{
//为了美观放在后面
}
};
核心算法解释
number operator+(number a)
{
number e;
int v_length = max(this->length,a.length)+1;
int *v = new int[v_length];
for(int i = 0;i < v_length;i++) v[i] = 0;
int carry = 0;
for(int i = 1;i <= min(this->length,a.length);i++)
{
int temp = this->value[this->length-i] + a.value[a.length-i] + carry;
carry = temp/10;
*(v + v_length - i) = temp%10;
}//在两个大数都有位的基础上进行一个加法
if(a.length < this->length) //判断哪个大数更长,则继续加进位
{
for(int i = a.length+1;i <= this->length;i++)
{
if(this->value[this->length-i]+carry < 10)
{
*(v+v_length-i) = this->value[this->length-i]+carry;
carry = 0;
}
else
{
*(v+v_length-i) = (this->value[this->length-i]+carry)%10;
carry = 1;
}
}
}
if(a.length > this->length)
{
for(int i = this->length+1;i <= a.length;i++)
{
if(a.value[a.length-i]+carry < 10)
{
*(v+v_length-i) = a.value[a.length-i]+carry;
carry = 0;
}
else
{
*(v+v_length-i) = (a.value[a.length-i]+carry)%10;
carry = 1;
}
}
}
if(carry == 1)
{
v[0] = 1;
e.set_value(v);//通过指针是否加1来决定是否取第一位
e.set_length(v_length);
return e;
}
else
{
e.set_value(v+1);
e.set_length(v_length-1);
return e;
}
}
number operator*(number c)
{
int flag = 0;
number result;
for(int i = this->length - 1;i >= 0;i--)
{
int carry = 0;
number temp1;
int *v = new int[c.length+this->length-i];//这里根据乘的哪一位使后面扩充0,例如,如果乘的百位,则扩充两个0,方便之后相加
for(int k = 0;k < c.length+this->length-i;k++) v[k] = 0;
for(int j = c.length - 1;j >= 0;j--)//双重迭代,先单独乘以一位,再把所有乘以一位的积加起来
{
int temp2 = this->value[i] * c.value[j] + carry;
carry = temp2 / 10;
v[j+1] = temp2 % 10;
}
if(carry != 0)
{
v[0] = carry;
temp1.set_length(c.length+this->length-i);
temp1.set_value(v);
}
else
{
temp1.set_length(c.length+this->length-i-1);
temp1.set_value(v+1);
}
if(i == this->length - 1)
{
result.set_length(temp1.length);
result.set_value(temp1.value);
}
else
{
result = result + temp1;
}
}
return result;
}
};
测试结果
int main()
{
string a,b;
number num1,num2,num3,num4;
int *temp1,*temp2;
int length1,length2;
cout<<"请输入第一个大数;";
cin>> a;
cout<<endl;
cout<<"请输入第二个大数;";
cin>> b;
cout<<endl;
length1 = a.size();
length2 = b.size();
num1.set_length(length1);
num2.set_length(length2);
temp1 = new int[length1];
temp2 = new int[length2];
for(int i = 0;i < length1;i++)
{
*(temp1+i) = a[i] - 48;
}
for(int i = 0;i < length2;i++)
{
*(temp2+i) = b[i] - 48;
}
num1.set_value(temp1);
num2.set_value(temp2);
num3 = num1 + num2;
num4 = num1 * num2;
cout<<"加法结果为:";
num3.show_value();
cout<<endl;
cout<<"乘法结果为:";
num4.show_value();
cout<<endl;
}
>请输入第一个大数: 99999999999999999999999999999999999999999999999999999999999999999999999999
>请输入第二个大数: 99999999999999999999999999999999999999999999999999999999999999999999999999999
加法结果为:100099999999999999999999999999999999999999999999999999999999999999999999999998
乘法结果为:9999999999999999999999999999999999999999999999999999999999999999999999999899900000000000000000000000000000000000000000000000000000000000000000000000001
总结
因为太久没用c++了我甚至对于一个for循环的条件编错了还半天看不出来,最后导致浪费了大量时间,这种初学者的错误我既然也会犯,还是长点心吧。除此之外就是对于类和指针的使用要稍微熟悉了一点,顺便力扣的题目得慢慢开始刷起来了。