重建operator()是重建的好习惯

Is overloading operator() for a reconstruction a good practice?

本文关键字:重建 好习惯 operator      更新时间:2023-10-16

我在想以下情况:

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;
    }
};

您可以看到,我的想法是使用操作员=覆盖内部数据和操作员()覆盖整个元素。我受到构造函数的启发,该构造器将允许A a(anOtherA);构建元素,我想覆盖此元素以进行重建。现在,我现在不这样做,如果这实际上是函数调用操作员。

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

简而言之,这不是良好的做法。这样的只是使引擎盖下的所做的事情混淆。

提供data的设置器,并使用您在重载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()的语义不是明确定义的(vs operator=()),您可以呼叫班级,看起来像" normal" 函数调用(这对模板大多有用将您的类型作为参数)。
但是我希望更多地做一些动作,而不是更改班级的内部状态。


关于样式,而不是 set/get getter/setter函数的前缀我更喜欢在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;
    }
    // ...
};

πάνταῥεῖ的好答案,请在这个答案中投票,而不是这个答案。

在您写作时,更重要的是,阅读更多C ,您会欣赏以自然,有意义的名字命名方法和功能的人。

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

X x;
Y y;
x(y);

我们甚至在查看XY的声明之前,X是某种函数对象(即它做某事),而Y是某种数据或状态对象 - 它喜欢对此做事,,或它提供数据或服务。

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

如果您对X::operator()(Y)的实现不会"与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上编写每项操作,这就是我所拥有的,这就像避免企业税一样,实际上是完全合法的,但是碰巧让其他人感到不安,因为他们最终会付钱自私的价格。