【问题标题】:How could I write c++ construction function clean and clear?我怎样才能写出干净利落的c++构造函数?
【发布时间】:2020-04-16 03:07:24
【问题描述】:

假设我的班级是这样的:

class Strt {
    public:
        int a{0};
        int b{0};

        Strt(int a, int b): a(a), b(b) {}
        Strt(Strt& s) {a = s.a; b = s.b;} // these two functions have same contents
        Strt(Strt&& s) {a = s.a; b = s.b;}
};

问题是左值初始化和右值初始化是相同的,这使得它不干净,因为一旦我想修改类成员变量,我需要以相同的方式修改这两个函数。代码是重复的。我怎样才能把它清理干净以便更好地阅读和维护?

编辑:

有些场合会调用这些构造函数:

Strt func() {return Strt(1, 2);}
vector<Strt> v;
Strt s(3, 4);
v.push_back(s); // call left construction function
v.emplace_back(func();} // call right construction function

还有一些场合需要修改类,比如我需要在里面添加int c;的新字段:

class Strt {
    public:
        int a{0};
        int b{0};
        int c{0};

        Strt(int a, int b, int c): a(a), b(b), c(c) {}
        Strt(Strt& s) {a = s.a; b = s.b; c = s.c;} // The two functions are duplicatedly modified in the same way
        Strt(Strt&& s) {a = s.a; b = s.b; c = s.c;}
};

Strt(Strt&amp;)Strt(Strt&amp;&amp;)的内容是否相同,我必须分别修改吗?

【问题讨论】:

  • 您的问题含糊不清。您能否列出构造函数的期望用法及其预期结果?此外,您可能希望将类和属性重命名为更具解释性的命名约定,这是最佳实践。
  • 有用的阅读:The rule of three/five/zero。详细说明何时需要特殊的复制和分配功能以及原因。

标签: c++ class object


【解决方案1】:

由于您的类不拥有任何可移动资源,因此没有理由创建单独的复制和移动构造函数。单个复制构造函数将执行相同的操作:

class Strt {
public:
    int a{0};
    int b{0};

    Strt(int a, int b): a(a), b(b) {}
    Strt(const Strt& s): a(s.a), b(s.b) {}
};

Live Demo

当然,因为你的拷贝构造函数除了成员拷贝之外什么都不做,你可以省略它,让编译器为你生成默认的:

class Strt {
public:
    int a{0};
    int b{0};

    Strt(int a, int b): a(a), b(b) {}
};

Live Demo

由于ab 都是公共的,并且您除了从构造函数参数初始化它们之外什么都不做,您可以完全省略您的构造函数并使用聚合初始化:

class Strt {
public:
    int a{0};
    int b{0};
};

Live Demo

【讨论】:

  • 你好,你好像只用{}构造对象,那我用()构造呢?我还不需要构造函数吗?
  • 你必须使用统一的初始化语法(使用{})来进行聚合初始化。它被称为“统一”是有原因的。其目的是将聚合、数组、对象的初始化语法与用户定义的构造函数统一起来。
【解决方案2】:

最干净的解决方案是删除用户声明的构造函数。不需要它们:

class Strt {
    public:
        int a{0};
        int b{0};
};

【讨论】:

  • 为什么?我还需要删除Strt(int a, int b) 吗?
  • 你不需要。但是如果你这样做,课程会更简单。越简单越好。
  • 是否支持这样的初始化:Strt s(1, 2); 如果我删除它?
  • 否,但它会允许Strt s{1, 2};
【解决方案3】:

在您的情况下,您可能会默认或省略您的复制/移动构造函数:

class Strt {
public:
    int a{0};
    int b{0};

    Strt(int a, int b): a(a), b(b) {}
    Strt(const Strt&) = default;
    Strt(Strt&&) = default;
};

一般情况下,您可以使用委托constructor

class Strt {
public:
    int a{0};
    int b{0};

    Strt(int a, int b): a(a), b(b) {}
    Strt(const Strt& rhs) : Strt(rhs.a, rhs.b) {}
    Strt(Strt&& rhs) : Strt(rhs) {}
};

【讨论】:

    猜你喜欢
    • 2014-03-31
    • 2022-11-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多