【问题标题】:Other way to prohibit a certain C++ class construction except than declaring the constructor private?除了将构造函数声明为私有之外,其他禁止某个 C++ 类构造的方法是什么?
【发布时间】:2011-11-11 03:56:51
【问题描述】:

假设我有一个带有一些 const 引用 成员变量的类,我想禁止某种类型的构造。所以我会声明相应的构造函数private。当然,构造函数必须初始化类的所有 const reference 成员变量。但是,这样做会导致代码看起来很奇怪:

class A {
};

class B {
  B(const A& a): host(a) {}
private:
  B():host(A()) {}   // This is ugly and not needed !!
  const A& host;
};

除了将构造函数声明为私有之外,还有其他方法可以禁止某种构造类型吗?我不想让编译器为我写一个构造函数。

【问题讨论】:

  • @Jon:天哪,太好了!我养成了将实现直接放入类定义的坏习惯。声明但不定义构造函数就可以了!非常感谢!
  • @Mat Hmm.. 你在我的问题中编辑了什么(以及为什么)?
  • 点击edited x minutes ago链接查看您问题的编辑历史。我刚刚将ctor 扩展为一个完整的单词以匹配您的其余文本。如果您想返回ctor,可以点击其中的“回滚”链接。
  • 好的,这个问题得到了回答(超出了我的要求)非常感谢大家!乔恩和纳瓦兹是第一个。乔恩删除了他的回答。所以,我想他不介意这一点,这一点归于纳瓦兹。但是,非常感谢 Martinhno 提供的 c++11 解决方案

标签: c++ construction


【解决方案1】:

不要定义这个:

B():host(A()) {}   // This is ugly and not needed !!

也就是说,以下应该做你想做的事:

class B {
  B(const A& a): host(a) {}
private:
  //B():host(A()) {}   // This is ugly and not needed !!
  const A& host;
};

这个想法是,如果您定义了一个带参数的构造函数,那么编译器不会生成默认构造函数。这意味着,上述类的实例不能默认创建!

 B b1; //error - needs default constructor which doesn't exist!
 B b2(a); //ok - only way to create an instance!

C++11解决方案

在 C++11 中,您可以明确告诉编译器不要生成特定的构造函数:

struct B
{
     B(const A &a) {}

     B() = delete;      //disable
};

不仅如此。还有更多,如下所述:

现在是有趣的部分

您还可以选择性地禁用 selected 类型的构造函数,这使delete 更有趣。考虑一下,

struct A
{
       A (int) {}
};

这个类的对象不仅可以使用int 参数创建,而且可以隐式转换为int 的任何类型。例如,

A a1(10);  //ok
A a2('x'); //ok - char can convert to int implicitly

B b; 
A a3(b); //ok - assume b provides user-defined conversion to int

现在假设,无论出于何种原因,我不希望 A 类的用户使用 charclass B 创建对象,幸运或不幸的是,它们可以隐式转换为 @ 987654335@,那么你可以禁用它们:

struct A
{
     A(int) {}
     A(char) = delete;      //disable
     A(const B&) = delete;  //disable
};

现在开始:

A a1(10);  //ok
A a2('x'); //error

B b; 
A a3(b); //error - assume (even if) b provides user-defined conversion to int

在线演示:http://ideone.com/EQl5R

错误信息很清楚:

prog.cpp:9:5: 错误:删除函数 'A::A(char)'
prog.cpp:10:5: 错误:删除函数 'A::A(const B&)'

【讨论】:

  • 您可以添加它以禁止构造函数,只需将其声明为私有(无需定义它)。例如,这对于禁止复制构造函数可能很有用。
  • @Nawaz 这很聪明!阅读代码时必须记住这一规则。你认为依赖这个规则是一个好习惯,比如说,完全省略声明而不是只声明它而不定义它?
  • 还有更多。删除的char 重载是其他类型的候选者,例如unsigned,所以现在只有int 的构造成功。 ideone.com/r9DD8(虽然错误信息很奇怪:如果只有一个候选人存在,那么歧义在哪里:))
【解决方案2】:

别管它了。只要您提供了自定义构造函数,就不会自动生成其他构造函数(复制构造函数除外)。

如果你想禁止 any 构造——最终得到一个只有静态成员的类——你可以简单地将构造函数声明为私有的,而不是定义它。这样的类在 C++ 中很少有用(因为你不能创建它的实例);我能想到的唯一目的是实现特征类:

template <typename T>
struct type_to_color {
    static char const* value() { return "blue"; }

private:
    type_to_color();
};

template <>
struct type_to_color<int> {
    // Integers are red!
    static char const* value() { return "red"; }

private:
    type_to_color();
}

char const* char_color = type_to_color<char>::value();
char const* int_color  = type_to_color<int>::value();

然而,这种情况极为罕见:C++ 中有大量 trait 类,但它们从不将其构造函数声明为 private,只是假设每个人都知道不要实例化它们。

【讨论】:

  • 您可以添加它以禁止构造函数,只需将其声明为私有(无需定义它)。例如,这对于禁止复制构造函数可能很有用。
  • @Luc 这个用例在 C++ 中并不存在。我添加了一个人工示例(特征类),但在正常使用中你永远不会删除它们的构造函数。
  • 我从未提到禁止所有构造函数,只是其中一些。在问题中提供的代码中,仍然会生成复制构造函数。如果 OP 想要禁止它,他必须将其声明为私有,但他不需要定义它(否则,他将遇到他描述的相同问题,即必须初始化成员 A
【解决方案3】:

我将发布 C++11 解决方案:删除构造函数。

class B {
  B() = delete;
  B(const A& a): host(a) {}
private:
  const A& host;
};

【讨论】:

  • 有趣。但是在声明另一个带参数的构造函数时,默认构造函数不是被删除了吗?
  • @ereOn:是的,确实如此。明确表示可能有助于表明您没有忘记这一点并且确实不想要,但这不是必需的。
【解决方案4】:

正如 Konrad Rudolph 所说:只要您提供自定义构造函数,就不会自动生成其他构造函数(复制构造函数除外)。

因此,其他选项是:

将构造函数声明为私有(这样你就不能从你的类继承),但不提供定义:

class B {
public:
  B(const A& a): host(a) {}
private:
  B(); // not implemented!
  const A& host;
};

或者在 C++11 中,正如 R. Martinho Fernandes 所说:

class B {
public:
  B() = delete;
  B(const A& a): host(a) {}
private:
  const A& host;
};

【讨论】:

    猜你喜欢
    • 2019-10-16
    • 2015-10-07
    • 1970-01-01
    • 2013-05-21
    • 2012-05-01
    相关资源
    最近更新 更多