【问题标题】:C++ Copy/Move constructor in policy based design [duplicate]基于策略的设计中的C ++复制/移动构造函数[重复]
【发布时间】:2017-09-01 18:49:49
【问题描述】:

在探索 C++ 中基于策略的设计模式时,我偶然发现了一个我找不到解决方案的问题:如何在不引用策略中的成员变量的情况下以通用方式为基于策略的类编写复制和移动构造函数上课?

这是一个例子:

class Foobase {
public:
  Foobase(int v) :val(v) { }
protected:
  int val;
};

template <typename Base>
class Foo : public Base {
public:
  Foo(int v):Base(v) { }
  // how can I initialize Base() class without referring to it's protected members?
  Foo(const Foo<Base>& other) :Base(other.val) { }
};

int main() {
  Foo<Foobase> foo(5);
  auto foo2 = foo;
}

在上面的代码中,class Foo的复制构造函数使用受保护的成员变量来初始化Base类。除了上述之外,还有其他方法可以初始化 Base 吗?在这种情况下,最佳做法是什么?

更新问题:

@LogicStuff 的回答澄清了问题的复制构造函数部分,但没有回答移动构造函数问题。请参阅更新后的示例代码,其中class Foo 也可以有成员变量。

class Foobase {
public:
  Foobase(int v) :val(v) { }
  Foobase(const Foobase&) = default;
  Foobase(Foobase&&) noexcept = default;
  Foobase& operator= (const Foobase&) = default;
  Foobase& operator= (Foobase&&) noexcept = default;
  void Print() const {
    std::cout << val << std::endl;
  }
protected:
  int val;
};

template <typename Base>
class Foo : public Base {
public:
  // works fine
  Foo(std::string str, int v):Base(v), name(str) { }

  // works fine
  Foo(const Foo<Base>& other) :Base(other), name(other.name) { }

  // I'm doubtful about this c'tor, if I move `other` for initializing Base,
  // how can I initialize `name` variable?
  Foo(Foo<Base>&& other)
    :Base(std::move(other)), name(std::move(other.name) /* will this be valid?? */) { }

  // can we have copy and assignment operator for this class?

  void Print() {
    std::cout << "name = " << name << std::endl;
    Base::Print();
  }

private:
  std::string name;
};

int main() {
  Foo<Foobase> foo("foo", 5);
  auto foo2 = std::move(foo);
  foo2.Print();
}

【问题讨论】:

  • 你为什么要首先定义复制构造函数?使用零规则。
  • 复制构造函数这里是一个例子,我将在实际用例场景中遵循5规则!
  • 不是五法则。 零规则。在您的情况下,Foobase 遵循零规则,Foo 中的所有成员都不需要特殊处理,因此您不要为Foo 类编写任何特殊成员因为默认的会做所有需要的。
  • 对不起,我没有定义所有的构造函数来拥有更小的示例代码

标签: c++ templates copy-constructor move-constructor policy-based-design


【解决方案1】:

你可以简单地使用Base的拷贝构造函数:

Foo(const Foo<Base>& other) : Base(other) { }

如果你不打算在那里做额外的事情,或者根本不定义它并留给编译器。

实际上,它可能看起来像这样,您的示例仍然可以编译:

template <typename Base>
class Foo : public Base {
public:
  using Base::Base;
};

修改后:

现在您必须补充一个带有两个参数的构造函数(就像您所做的那样):

template <typename Base>
class Foo : public Base {
public:
  Foo(std::string str, int v) : Base(v), name(str) { }

  void Print() {
    std::cout << "name = " << name << std::endl;
    Base::Print();
  }

private:
  std::string name;
};

但您还定义了特殊的成员函数,否则编译器将生成相同的函数(这意味着它们是正确的)。您的原始示例也是如此。 Foo 的两个版本都是可移动构造的。

【讨论】:

  • 感谢@LogicStuff 的回答。它确实回答了我关于复制构造函数的问题,但可能不回答移动构造函数的一部分。也许我错过了什么?请参阅更新的问题。谢谢!
  • 请务必遵守 3/5/0 的规则。这个问题纯粹是因为你没有这样做。
  • 抱歉造成混淆,我只是没有将所有构造函数定义为具有更小的示例代码。
  • 您的解决方案是根本不定义构造函数。很好,但我想明确定义或删除构造函数。您的解决方案没有回答这个问题。
  • “这意味着他们是正确的”回答了这部分。
猜你喜欢
  • 2023-03-11
  • 1970-01-01
  • 1970-01-01
  • 2023-03-03
  • 2021-10-13
  • 2016-02-20
  • 2018-03-12
  • 2014-01-02
  • 2016-06-20
相关资源
最近更新 更多