6

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

class A {
};

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

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

4

4 回答 4

14

简单地不要定义这个:

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

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

现在有趣的部分

您还可以选择性地禁用所选类型的构造函数,这会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

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

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&)'

于 2011-09-06T09:18:41.107 回答
11

把它放在外面。一旦您提供了自定义构造函数,就不会自动生成其他构造函数(复制构造函数除外)。

如果你想禁止任何构造——最终得到一个只有静态成员的类——你可以简单地将构造函数声明为私有,而不是定义它。这样的类在 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,只是假设每个人都知道不实例化它们。

于 2011-09-06T09:18:45.267 回答
2

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

class B {
  B() = delete;
  B(const A& a): host(a) {}
private:
  const A& host;
};
于 2011-09-06T09:29:54.043 回答
0

正如 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;
};
于 2011-09-06T09:36:53.407 回答