写这篇博文的时候我真的真的真的了百感交集
事情是这样的,这份作业我写了不下6个小时,就是因为各种细节的错误,各种bug层出不穷,一个bug修完又出现新的bug,一次次的崩溃,最终还是磨出来了……
来看题:定义:类模板T_Counter,实现基本数据类型的+、-、*、=、>>、<<运算;类模板T_Counter 实现向量运算。
读题一开始觉得这道题人畜无害,写个模板就完事了,但实际编程过程中问题是真的不少。
首先定义类模板T_Counter
template<typename T>
class T_Counter
{
private:T a;
public:
void Print() { cout << a << endl; }
T_Counter() {}
T_Counter(T x) { a = x; }
};
就是上面这个样子,这个时候苯人还没有意识到问题的严重性。就是很简单的一个模板类,顺手写个构造函数和print函数。
之后就是实现基本数据类型的+-*/<<>>运算,这边我就遇到了第一个细节:在每个友元函数的声明之前,都要写上模板,而不能直接使用类模板中的数据类型。
template<typename T>
friend T_Counter<T> operator+(const T_Counter<T>& tc1, const T_Counter<T>& tc2);
template<typename T>
friend T_Counter<T> operator-(const T_Counter<T>& tc1, const T_Counter<T>& tc2);
template<typename T>
friend T_Counter<T> operator*(const T_Counter<T>& tc1, const T_Counter<T>& tc2);
template<typename T>
friend T_Counter<T> operator/(const T_Counter<T>& tc1, const T_Counter<T>& tc2);
template<typename T>
friend T_Counter<T> operator<<(const T_Counter<T>& tc1, const T_Counter<T>& tc2);
template<typename T>
friend T_Counter<T> operator>>(const T_Counter<T>& tc1, const T_Counter<T>& tc2);
T_Counter& operator=(T_Counter tc)
{
this->a = tc.a;
return *this;
}
当然这个bug没有卡我很久,报错之后就马上注意到了(忘了截图了,不然说实话20多个报错还是挺壮观的)写完之后就是上面这个样子(函数体的写法我就略过了,反正后面有完整代码的)写到这里还是有惊无险。我当时甚至在想这道题有没有写的必要,看起来只要把以上内容copy一遍再稍作修改就能结束了
template<typename T>
class T_Vector {
private:
T* p;
int size;
public:
T_Vector& operator=(const T_Vector& tc)
{
this->size = tc.size;
this->p=tc.p;
return *this;
}
void Print()
{
for (int i = 0; i < size; i++)
cout << p[i];
}
T_Vector(int n) {
size = n;
p = new T[size];
}
T_Vector(int s, T* pp) {
size = s;
p = pp;
}
~T_Vector() {
delete[] p; size = 0;
}
T& operator[](int i);
template<typename U>friend T_Vector<U> operator+(const T_Vector<U>& tc1, const T_Vector<U>& tc2);
几乎都是直接照搬上面的T_Counter的代码,上面的能跑理论上这边也能跑。但
现实就是给我弹了个这个,特别眼熟的框,我之前一定遇到过一样的问题……
于是我就在这边改了很久。设断点、删改代码,初步排查是+的重载出了问题。我当时以为单纯是我函数体或者函数声明有问题,于是就一遍遍地改。翻书、查csdn,甚至问chatgpt。一开始是对着别人的代码修改,但是修改了好几个版本都没有解决问题。后来甚至干脆复制别人的函数,也是编译出问题。在当时的我眼中这就是个很玄学的问题了,因为别人的代码全篇能跑,但别人的函数单拿过来给我跑不了(其实这个时候就应该意识到不是这个重载运算符出问题了,但是由于删掉这一部分能完美地跑出结果,所以当时的我就一直纠结在这个地方)在这个地方几乎花了我写这个程序的90%时间……
最后我实在解决不了,想着先把这个弹窗弄明白吧,于是就直接查了下这个弹窗:
https://blog.csdn.net/qq_59278530/article/details/127163331
查到了上面这个东东,总结来说就是在调用函数的时候没有没有使用引用作为参数,导致类在实例化后重复析构的问题。为了确认我是否也遇到了这个问题,我直接删掉了我的析构函数,果不其然,跑通了。
现在定位到是析构函数出了问题,但是我仔细检查了一遍,由于我良好的编程习惯,我的参数全都是const&,很规范的用法。问题到这边似乎又进入了死胡同……毕竟是析构函数出了问题,这种小型的程序,析构函数的存在意义其实没有特别大,所以一开始的我选择直接删掉析构函数
本来已经打算摆烂交作业了,但是我的脑海中突然闪过一个画面,那是之前一次写博文,我清楚地记得我在博文中强调了Vector类动态数组地拷贝构造函数需要进行特殊的处理……
https://blog.csdn.net/2301_77136128/article/details/129900174?spm=1001.2014.3001.5502
↑↑于是我参考了……我自己之前写的博文……
(坏了,那还是我第一次写详解)
原来出问题的是拷贝构造函数
T_Vector(const T_Vector& t)
{
this->size = t.size;
this->p = t.p;
this->p = new T[t.size];
for (int i = 0; i < t.size; i++)
this->p[i] = t.p[i];
}
按照之前博文说的方法改完,豁然开朗
难怪记得这个报错弹窗十分眼熟,原来我在那个时候就已经遇到了这个问题……
以下就是完整代码了;但我还要再啰嗦几句:由于>><<已经重载,cin,cout在不对类的实例上进行操作时有概率报错,于是我也是使用简单粗暴的方法:把报错的cin,cout改为printf、scanf,用c解决c++问题(doge)
具体printf和scanf的用法自行csdn(苯人也不太熟,只是碰巧会用一点)
#include<iostream>
using namespace std;
template<typename T>
class T_Counter
{
private:T a;
public:
void Print() { cout << a << endl; }
template<typename T>
friend T_Counter<T> operator+(const T_Counter<T>& tc1, const T_Counter<T>& tc2);
template<typename T>
friend T_Counter<T> operator-(const T_Counter<T>& tc1, const T_Counter<T>& tc2);
template<typename T>
friend T_Counter<T> operator*(const T_Counter<T>& tc1, const T_Counter<T>& tc2);
template<typename T>
friend T_Counter<T> operator/(const T_Counter<T>& tc1, const T_Counter<T>& tc2);
template<typename T>
friend T_Counter<T> operator<<(const T_Counter<T>& tc1, const T_Counter<T>& tc2);
template<typename T>
friend T_Counter<T> operator>>(const T_Counter<T>& tc1, const T_Counter<T>& tc2);
T_Counter& operator=(T_Counter tc)
{
this->a = tc.a;
return *this;
}
T_Counter() {}
T_Counter(T x) { a = x; }
};
template<typename T>
T_Counter<T>operator+(const T_Counter<T>& tc1, const T_Counter<T>& tc2)
{
T r = tc1.a + tc2.a;
return T_Counter<T>(r);
}
template<typename T>
T_Counter<T>operator-(const T_Counter<T>& tc1, const T_Counter<T>& tc2)
{
T r = tc1.a - tc2.a;
return T_Counter<T>(r);
}
template<typename T>
T_Counter<T>operator*(const T_Counter<T>& tc1, const T_Counter<T>& tc2)
{
T r = tc1.a * tc2.a;
return T_Counter<T>(r);
}
template<typename T>
T_Counter<T>operator/(const T_Counter<T>& tc1, const T_Counter<T>& tc2)
{
T r = tc1.a / tc2.a;
return T_Counter<T>(r);
}
template<typename T>
T_Counter<T>operator>>(const T_Counter<T>& tc1, const T_Counter<T>& tc2)
{
T r = tc1.a >> tc2.a;
return T_Counter<T>(r);
}
template<typename T>
T_Counter<T>operator<<(const T_Counter<T>& tc1, const T_Counter<T>& tc2)
{
T r = tc1.a << tc2.a;
return T_Counter<T>(r);
}
template<typename T>
class T_Vector {
private:
T* p;
int size;
public:
T_Vector(const T_Vector& t)
{
this->size = t.size;
this->p = t.p;
this->p = new T[t.size];
for (int i = 0; i < t.size; i++)
this->p[i] = t.p[i];
}
T_Vector& operator=(const T_Vector& tc)
{
delete[]p;
this->size = tc.size;
p = new T[size];
for (int i = 0; i < size; i++)
p[i] = tc.p[i];
return *this;
}
void Print()
{
for (int i = 0; i < size; i++)
cout << p[i];
}
T_Vector(int n) {
size = n;
p = new T[size];
}
T_Vector(int s, T* pp) {
size = s;
p = pp;
}
~T_Vector() {
delete[] p; size = 0;
}
T& operator[](int i);
template<typename U>friend T_Vector<U> operator+(const T_Vector<U>& tc1, const T_Vector<U>& tc2);
template<typename U>friend T_Vector<U> operator-(const T_Vector<U>& tc1, const T_Vector<U>& tc2);
template<typename U>friend T_Vector<U> operator*(const T_Vector<U>& tc1, const T_Vector<U>& tc2);
template<typename U>friend T_Vector<U> operator/(const T_Vector<U>& tc1, const T_Vector<U>& tc2);
template<class T_Vector>friend ostream& operator<<(ostream& out, const T_Vector& p);
template<class T_Vector>friend istream& operator>>(istream& in, const T_Vector& p);
};
template <typename T>
T& T_Vector<T>::operator[](int i) {
if (i < 0 || i >= size) {
printf("error\n");
exit(0);
}
return p[i];
}
template<class T_Vector>
ostream& operator<<(ostream& out, const T_Vector& p)
{
for (int i = 0; i < p.size; i++)
{
cout << p.p[i];
printf(" ");
}
cout << endl;
return out;
}
template<class T_Vector>
istream& operator>>(istream& in, const T_Vector& p)
{
printf("请输入数据\n");
for (int i = 0; i < p.size; i++)
{
cin >> p.p[i];
}
return in;
}
template<class U>
T_Vector<U>operator+(const T_Vector<U>& tc1, const T_Vector<U>& tc2)
{
int s = tc1.size;
U* p;
p = new U[s];
T_Vector<U> tmp(s, p);
for (int i = 0; i < s; i++)
{
p[i] = tc1.p[i] + tc2.p[i];
}
return tmp;
}
template<typename U>
T_Vector<U>operator-(const T_Vector<U>& tc1, const T_Vector<U>& tc2)
{
int s = tc1.size;
U* p;
p = new U[s];
T_Vector<U> tmp(s, p);
for (int i = 0; i < s; i++)
{
p[i] = tc1.p[i] - tc2.p[i];
}
return tmp;
}
template<typename U>
T_Vector<U>operator*(const T_Vector<U>& tc1, const T_Vector<U>& tc2)
{
int s = tc1.size;
U* p;
p = new U[s];
T_Vector<U> tmp(s, p);
for (int i = 0; i < s; i++)
{
p[i] = tc1.p[i] * tc2.p[i];
}
return tmp;
}
template<typename U>
T_Vector<U>operator/(const T_Vector<U>& tc1, const T_Vector<U>& tc2)
{
int s = tc1.size;
U* p;
p = new U[s];
T_Vector<U> tmp(s, p);
for (int i = 0; i < s; i++)
{
p[i] = tc1.p[i] / tc2.p[i];
}
return tmp;
}
int main()
{
T_Counter<double>a(5), b(6.24);
T_Counter<double>c = a + b;
printf("a+b=");
c.Print();
c = a - b;
printf("a-b=");
c.Print();
c = a * b;
printf("a*b=");
c.Print();
c = a / b;
printf("a/b=");
c.Print();
T_Vector<double> x(5);
cin >> x;
T_Vector<double>y(5);
cin >> y;
printf( "x+y=\n");
cout << x + y;
printf("x-y=\n");
cout << x - y;
printf("x*y=\n");
cout << x * y;
printf("x/y=\n");
cout << x + y;
}