C ++:关于重载运算符的后续运算

时间:2016-10-20 22:39:31

标签: c++ class operator-overloading

#include <iostream>
#include <vector>
using namespace std;


void testfn(double* v1, double *v2, double *v3, int n);//I must use this function

class CLS{
private:
    vector<double> v;
public:
    CLS(vector<double> vin);
    CLS operator+(CLS & A);
    CLS operator*(CLS & A);
};

CLS::CLS(vector<double> vin)
{
    v=vin;
}

CLS CLS::operator*(CLS &A){
    //assuming the two vectors have the same length
    vector<double> vtmp(v.size(),0);
    testfn(&*A.v.begin(),&*v.begin(),&*vtmp.begin(),(int)A.v.size());
    CLS C(vtmp);
    return C;
}

CLS CLS::operator+(CLS &A){
    //assuming the two vectors have the same length
    vector<double> vtmp(v.size(),0);
    testfn(&*A.v.begin(),&*v.begin(),&*vtmp.begin(),(int)A.v.size());
    CLS C(vtmp);
    return C;
}

void testfn(double* v1, double *v2, double *v3, int n)
{
    for (int i=0;i<n;i++)
    {
        *v3=*v1+*v2;
        ++v1;
        ++v2;
        ++v3;
    }
}

int main(){
    vector<double> v1(100,1.0), v2(100,2.0), v3(100,0.0);
    CLS C1(v1),C2(v2),C3(v3);
    CLS C4=C1*(C1+(C2*C3+C2))*C1*C2*C3+C1+C2+C3;
    return 0;
}

我创建了CLS类并定义了两个运算符+和*。我想使用这些运算符就像我们如何使用+和*来表示整数和双精度。因此,我在主CLS C4=C1*(C1+(C2*C3+C2))*C1*C2*C3+C1+C2+C3;中有一个测试行。但是,在使用gcc编译此代码时,我遇到了大量错误。我对运算符重载的规则不够熟悉。我应该如何修改*和+的定义(可能只是参数?),以便CLS C4=C1*(C1+(C2*C3+C2))*C1*C2*C3+C1+C2+C3;有效?

补充:我不知道如何对operator +和*使用const参数,因为这两个运算符的定义涉及另一个函数testfn,其参数是double *而不是const double *。此外,我不想更改testfn定义中的任何部分,因为在我的实际代码中它对应于LAPACK中的一个函数,我绝对无权更改。

3 个答案:

答案 0 :(得分:1)

最好将case class CsvFile(lines: Map[String, List[String]], rowCount: Int = 0) { def merge(line: Map[String, String]): CsvFile = { val orig = lines.withDefaultValue(List.fill(rowCount)("")) val current = line.withDefaultValue("") val newLines = (lines.keySet ++ line.keySet) map { k => (k, orig(k) :+ current(k)) } CsvFile(newLines.toMap, rowCount + 1) } } operator+定义为友元函数,这样如果存在从其他类型到operator*的隐式转换,则可以使用运算符。如果它是一个成员函数,那么如果第一个操作数不是CLS,则不会找到它。

CLS

答案 1 :(得分:1)

你应该在你的代码中使用空格,阅读起来很糟糕。不要对类型名和变量使用大写字母,这也很难阅读。

这不是必需的,而是一个小优化,通过引用传递构造函数参数,然后在构造函数初始化列表中初始化v成员(而不是通过在正文中分配它):

CLS::CLS(const vector<double>& vin) : v(vin)
{
}

我会添加一个新的构造函数,它会获得所需的大小,并立即将v成员的大小调整为,这样可以使代码更简单:

CLS::CLS(int n) : v(n, 0)
{
}

首先将const添加到函数参数和成员函数本身:

CLS CLS::operator*(const CLS& a) const {
                   ^^^^^         ^^^^^

然后默认为结果构造一个空的C对象,并使用所需大小的向量成员:

    //assuming the two vectors have the same length
    CLS result(v.size());

如果您创建数据向量的副本并处理这些副本,那么您可以使成员函数及其参数为const:

    vector<double> v1 = a.v;
    vector<double> v2 = v;

现在你可以获得那些向量中的数据的非常量指针,你可以直接将输出写入C.v而不是写入vtmp,然后将其复制到返回的对象中: / p>

    testfn(&*v1.begin(), &*v2.begin(), &*result.v.begin(), v.size());

最后返回结果:

    return result;
}

其他功能完全相同:

CLS CLS::operator+(const CLS& a) const {
    //assuming the two vectors have the same length
    CLS result(v.size());
    vector<double> v1 = a.v;
    vector<double> v2 = v;
    testfn(&*v1.begin(), &*v2.begin(), &*result.v.begin(), v.size());
    return result;
}

现在这将能够接受const参数,因此应该使用由每个C1+C2C3*C4表达式创建的临时对象。

由于数据的额外副本,代码的效率稍差,但构造函数中的优化有助于此。如果你能够使用C ++ 11,那么即使那些效率低下也可以解决,但需要做更多的工作。

首先,C ++ 11提供vector<T>::data()来获取指针,这比&*v.begin()更清晰。 (它不是C ++ 11之前的C ++标准的一部分,但GCC甚至为C ++ 98提供了它)。您可以更改上面显示的代码,使用v.data()代替&*v.begin(),如下所示。

在C ++ 11中,您可以通过将(非常量)右值引用绑定到临时对象来添加对临时对象起作用的其他重载。因为rvalue引用允许您对临时对象进行非const访问,所以您不需要复制其数据来获取非常量指针,并且可以直接使用它们。除了上面显示的原始重载之外,还要添加这些运算符重载:

CLS CLS::operator+(CLS&& a) && {
    //assuming the two vectors have the same length
    CLS result(v.size());
    testfn(a.v.data(), v.data(), result.v.data(), v.size());
    return result;
}

CLS CLS::operator*(CLS&& a) && {
    //assuming the two vectors have the same length
    CLS result(v.size());
    testfn(a.v.data(), v.data(), result.v.data(), v.size());
    return result;
}

这可以避免在算术表达式创建的中间临时对象中创建任何副本。我还发现很多更容易理解和更容易阅读。

完整的工作示例位于http://coliru.stacked-crooked.com/a/6e40d20eb7f1e9fc

答案 2 :(得分:1)

使用testfn所有params非const的不寻常要求有点奇怪,但是......嗯.. 不情愿地接受不可接受的情况复杂表达式 - testfn的前两个参数需要const double*

基本原理: C ++标准要求临时工具绑定到const references - 某些interesting details here

@Resorter说:

  

&#34;感谢您告诉我,我想学习。但你确定解决了我的问题吗?我真的想先解决这个问题。&#34;

[其中是&#39;移动构造函数&#39;和&#39;移动作业&#39;]

以下&#34; fish&#34;假设您已经阅读/学习了捕鱼move constructormove assign以及rules of 5/3/0

补充学习材料:copy elision - 允许编译器跳过复制/移动构造函数,即使它们会产生副作用。

// some implementations
void testfn0(const double* v1, const double *v2, double *v3, int n) {
  for(int i=0; i<n; i++) {
    v3[i]=v1[i]+v2[i];
  }
}

void testfn1(double* v1, double *v2, double *v3, int n) {
  for(int i=0; i<n; i++) {
    v3[i]=v1[i]*v2[i];
  }
}

class CLS {
  std::vector<double> v;
public:
  // constructor taking a const reference
  CLS(const std::vector<double>& in) : v(in) {
    std::cout << "copy vec" << std::endl;
  }

  // extra constructor with rvalue reference: it will "canibalize" the parameter
  CLS(std::vector<double>&& in) : v(in) {
    std::cout << "move vec" << std::endl;
  }

  // Rule of 5 applied
  // Copy constructor
  CLS(const CLS& other) : v(other.v) {
    std::cout << "copy CLS" << std::endl;
  }
  // Move constructor
  CLS(CLS&& other) : v(std::move(other.v)) {
    std::cout << "move CLS" << std::endl;
  }
  ~CLS() { }

  // Copy assgn
  CLS& operator=(const CLS& o) {
    this->v=o.v;
    std::cout << "assgn CLS" << std::endl;
    return *this;
  }
  // Move assgn
  CLS& operator=(CLS&& other) {
    this->v=std::move(other.v);
    std::cout << "move CLS" << std::endl;
    return *this;
  }

  // WILL NOT WORK WITHOUT const FOR COMPLEX EXPRESSIONS
  //                       |
  //              ----------
  //              V
  CLS operator+(const CLS& rhs) {
    std::vector<double> vtmp(v.size(),0);
    testfn0(&*rhs.v.begin(),&*v.begin(),&*vtmp.begin(),(int)rhs.v.size());

    CLS ret(std::move(vtmp));
    return ret;
  }

  // WILL NOT WORK WITHOUT const FOR COMPLEX EXPRESSIONS
  //                       |
  //              ----------
  //              V
  CLS operator*(const CLS& rhs) {
    std::vector<double> vtmp(v.size(),0);
    testfn1(&*rhs.v.begin(),&*v.begin(),&*vtmp.begin(),(int)rhs.v.size());

    CLS ret(std::move(vtmp));
    return ret;
  }
};

int main() {
  std::cout << "\n--- inits " << std::endl;
  CLS a(std::vector<double>{1,2,3}); // move vec
  CLS b(std::vector<double>{3,2,1}); // move vec

  std::cout << "\n--- add " << std::endl;
  CLS c=a+b; // move vec and 'silence' (copy elision)
  std::cout << "\n--- mul " << std::endl;
  CLS d=a*b; // move vec and 'silence' (copy elision)

  std::cout << "\n--- copy " << std::endl;
  CLS m=c; // Copy CLS - constructor

  std::cout << "\n--- move " << std::endl;
  CLS n=std::move(d); // Move CLS - constructor

  std::cout << "\n--- assgn (d=c) and copy (x=c)" << std::endl;
  CLS x=d=c;
}