重载operator()重建是一个好习惯吗?

时间:2016-12-14 17:57:34

标签: c++ operator-overloading

我在考虑以下情况:

class A {
    private:

    std::string id;
    std::array<std::string, 128> data;

    public:

    A(const std::string& id) : id(id) {}
    A(const A& other) : id(other.id), data(other.data) {}
    virtual ~A(){}

    //to override the intern data
    A& operator=(const A& other) {

        this->data = other.data;

        return *this;
    }

    //to override the whole element
    A& operator()(const A& other) {

        this->id = other.id;
        this->data = other.data;

        return *this;
    }
};

正如您所看到的,我的想法是使用operator =覆盖内部数据,使用operator()来覆盖整个元素。我受到构造函数的启发,它允许A a(anOtherA);构造元素,我想重写它以进行重构。现在我现在不知道这是否会智能重载,因为它实际上是函数调用操作符。

2 个答案:

答案 0 :(得分:3)

  

重载operator()重建是一种好习惯吗?

简而言之,这不是良好做法。这只是模糊了引擎盖下的内容。

data提供一个setter并使用您在重载operator()中提供的代码来实现赋值operator=(),这将提供更清晰且自然期望的语义:

class A {
    private:

    std::string id;
    std::array<std::string, 128> data;

    public:

    A(const std::string& id) : id(id) {}
    A(const A& other) : id(other.id), data(other.data) {}
    ~A(){}

    //to override the intern data
    A& operator=(const A& other) {
        id = other.id;
        data = other.data;

        return *this;
    }

    //to override the intern data
    void setData(const A& other) {
         data = other.data;
    }
    void setData(const std::array<std::string, 128>& data_) {
         data = data_;
    }
};

operator()的语义并没有明确定义(与operator=()相比),除了你可以调用你的类看起来像“普通”函数调用(对于将类型作为参数的模板最常用) 但我希望更多的是做一些动作而不是改变类的内部状态。

关于样式,而不是getter / setter函数的set / get前缀,我更喜欢在c ++标准库中完成的操作(例如,使用std::ios_base::flags()属性):

class A {
private:
    // ...
    std::array<std::string, 128> data_;
public:
    const std::array<std::string, 128>& data() const {
         return data_;
    }
    void data(const std::array<std::string, 128>& data) {
         data_ = data;

    }
    // ...
};

答案 1 :(得分:3)

来自πάνταῥεῖ的答案非常好所以请回答这个答案,而不是这个答案。

在你写作时,更重要的是,阅读更多c ++,你会发现那些用自然,有意义的名字命名方法和功能的人。

对于我们大多数人来说,如果我们看到这样的代码:

X x;
Y y;

x(y);

在查看XY的声明之前,我们会认为X是某种功能对象(即它有所作为)和Y是某种数据或状态对象 - 它喜欢完成任务,或者提供数据或服务。

作为旁注,Haskell程序员自然会认为Y也是一个函数,但这是另一个故事。

如果你的X::operator()(Y)的实现没有“对Y做X类型的东西”那么它可能不恰当地命名。

如果Y实际上代表X的新状态,并且X打算使用Y中的数据“重置”自身,那么应该调用该方法。 .. reset

X x;
Y y;

x.reset(y);  //ok, this is telling a better story

我们可以用合理的名字用我们的代码讲述一个叙述:

void processResults(XFactory& factory, std::istream& is) {
    while(is) {
        auto x = X::createFrom(factory);
        x.collectNResults(is, 10);
        auto a = x.takeAverage();
        storeAverage(a);
        x.reset(y);
    }
}

现在,即使没有查阅各种类的定义,我也可以了解一般的叙述。它更容易在眼睛上,我将能够磨练我需要看到的位数比以下更快:

void processResults(XFactory& factory, std::istream& is) {
    while(is) {
        auto x = X(factory);
        x(is, 10);
        auto a = x();
        x(averageStore);
        x(y);
    }
}

如果我根据呼叫运营商在X上编写每一项操作,这就是我所拥有的,这与公司避税一样,实际上是完全合法的,但却恰好打扰了其他人,因为他们最终支付了你自私的价格。