我正在编写一个模板Polynom<T>
类,其中T
是其系数的数字类型。
多项式的系数存储在std::vector<T> coefficients
中,其中coefficients[i]
对应于实数多项中的x^i
。 (因此x的幂次数递增)。
保证coefficients
向量始终包含至少一个元素。 - 对于零多项式,它是T()
。
我想重载operator[]
来执行以下操作:
coefficients.at(i)
- 并且合理地返回0表示所有其他指数,而不是抛出。我遇到的主要问题如下:
1
如何区分读取案例和写入案例?有一个人在没有解释的情况下离开了我,但说写了两个版本:
coefficients.size()
不够。但是,我认为编译器更喜欢在读取情况下的const版本,不是吗?
2
我想确保const T& operator[] (int index) const;
T& operator[] (int index);
向量中没有存储任何尾随零。所以我必须事先知道,“之前”我返回了我的系数的可变coefficients
,用户想要分配的值。而且我知道T&
没有得到第二个论点。
显然,如果这个值不是零(不是T()),那么我必须调整我的向量大小并将适当的系数设置为传递的值。
但是我不能事先做到(在从operator[]
返回T&
之前),因为如果要分配的值是T(),那么,如果我提前调整了系数向量,它最终会有很多尾随的“零”。
当然,我可以在类的每个其他函数中检查尾随零,并在这种情况下删除它们。对我来说似乎是一个非常奇怪的决定,我希望每个函数都开始工作,假设它的大小&gt;在向量的末尾没有零。 1。
你能否告诉我这个问题的具体解决方案?
我听说过一些内容类可以隐式转换为operator[]
并且重载T&
,但我缺乏细节。
非常感谢你!
答案 0 :(得分:3)
您可以尝试一种选择(我没有测试过):
template<typename T>
class MyRef{
private:
int index;
Polynom<T>*p;
public:
MyRef(int index, Polynom<T>*p) : index(index), p(p) { }
MyRef<T>& operator=(T const&t); //and define these appropriately
T operator T() const;
};
并定义:
MyRef<T> operator[](int index){
return MyRef<T>(index, this);
}
这样,当您为“引用”赋值时,它应该可以访问多项式中所有需要的数据,并采取适当的操作。
我对你的实现不够熟悉,所以我将举一个非常简单的动态数组的例子,其工作原理如下:
int index
;以前没有写过的元素应该读作0
; 0
。#include <cstdlib>
#include <iostream>
using namespace std;
template<typename T>
class my_array{
private:
T* _data;
int _size;
class my_ref{
private:
int index;
T*& obj;
int&size;
public:
my_ref(T*& obj, int&size, int index)
: index(index), obj(obj), size(size){}
my_ref& operator=(T const& t){
if (index>=size){
obj = (T*)realloc(obj, sizeof(T)*(index+1) );
while (size<=index)
obj[size++]=0;
}
obj[index] = t;
return *this;
}
//edit:this one should allow writing, say, v[1]=v[2]=v[3]=4;
my_ref& operator=(const my_ref&r){
operator=( (T) r);
return *this;
}
operator T() const{
return (index>=size)?0:obj[index];
}
};
public:
my_array() : _data(NULL), _size(0) {}
my_ref operator[](int index){
return my_ref(_data,_size,index);
}
int size() const{ return _size; }
};
int main(){
my_array<int> v;
v[0] = 42;
v[1] = 51;
v[5] = 5; v[5]=6;
v[30] = 18;
v[2] = v[1]+v[5];
v[4] = v[8]+v[1048576]+v[5]+1000;
cout << "allocated elements: " << v.size() << endl;
for (int i=0;i<31;i++)
cout << v[i] << " " << endl;
return 0;
}
这是一个非常简单的例子,目前的形式并不是很有效,但它应该证明这一点。
最后,您可能希望重载operator&
以允许*(&v[0] + 5) = 42;
之类的内容正常工作。对于此示例,您可以让operator&
提供my_pointer
来定义operator+
以对其index
字段进行算术运算并返回新的my_pointer
。最后,您可以重载operator*()
以返回my_ref
。
答案 1 :(得分:2)
对此的解决方案是代理类(未经测试的代码如下):
template<typename T> class Polynom
{
public:
class IndexProxy;
friend class IndexProxy;
IndexProxy operator[](int);
T operator[](int) const;
// ...
private:
std::vector<T> coefficients;
};
template<typename T> class Polynom<T>::IndexProxy
{
public:
friend class Polynom<T>;
// contrary to convention this assignment does not return an lvalue,
// in order to be able to avoid extending the vector on assignment of 0.0
T operator=(T const& t)
{
if (theIndex >= thePolynom.coefficients.size())
thePolynom.coefficients.resize(theIndex+1);
thePolynom.coefficients[theIndex] = t;
// the assignment might have made the polynom shorter
// by assigning 0 to the top-most coefficient
while (thePolynom.coefficients.back() == T())
thePolynom.coefficients.pop_back();
return t;
}
operator T() const
{
if (theIndex >= thePolynom.coefficients.size())
return 0;
return thePolynom.coefficients[theIndex];
}
private:
IndexProxy(Polynom<T>& p, int i): thePolynom(p), theIndex(i) {}
Polynom<T>& thePolynom;
int theIndex;
}
template<typename T>
Polynom<T>::IndexProxy operator[](int i)
{
if (i < 0) throw whatever;
return IndexProxy(*this, i);
}
template<typename T>
T operator[](int i)
{
if (i<0) throw whatever;
if (i >= coefficients.size()) return T();
return coefficients[i];
}
显然,上面的代码没有得到优化(特别是赋值运算符显然有优化空间)。
答案 2 :(得分:1)
您无法区分具有运算符重载的读取和写入。您可以做的最好的事情是区分const
设置中的使用情况和非const
设置,这是您的代码段所做的。所以:
Polynomial &poly = ...;
poly[i] = 10; // Calls non-const version
int x = poly[i]; // Calls non-const version
const Polynomial &poly = ...;
poly[i] = 10; // Compiler error!
int x = poly[i] // Calls const version
因此,对于您的两个问题,答案似乎都是单独的set
和get
函数。
答案 3 :(得分:1)
我看到了两个问题的解决方案:
而不是将系数存储在std::vector<T>
中,而不是将它们存储在std::map<unsigned int, T>
中。这样您将只存储非零系数。您可以创建自己的基于std::map
的容器,该容器将消耗存储在其中的零。这样,您还可以为x ^ n格式的多项式保存一些存储,其中包含大n。
添加一个内部类,用于存储索引(幂)和系数值。您将从operator[]
返回对此内部类的实例的引用。内部类将覆盖operator=
。在重写的operator=
中,您将获取存储在内部类实例中的索引(幂)和系数,并将它们刷新到存储系数的std::vector
。
答案 4 :(得分:0)
这是不可能的。我能想到的唯一方法是提供一个特殊的成员函数来添加新的系数。
编译器通过查看const
的类型来决定const
和非Polynom
版本,而不是通过检查对返回值执行的操作类型。