除了声明构造函数私有之外,禁止某些C ++类构造的其他方法?

时间:2011-09-06 09:13:55

标签: c++ construction

假设我有一个带有 const reference 成员变量的类,我想禁止某种类型的构造。所以我会声明相应的构造函数 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 个答案:

答案 0 :(得分: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

现在假设,无论出于何种原因,我都不希望类A的用户创建charclass B的对象,幸运或遗憾的是隐式地< / em>转换为int,然后您可以将它们禁用为:

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

答案 1 :(得分: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 ++中很丰富,但它们从未将它们的构造函数声明为private,它只是假设每个人都知道不实例化它们。

答案 2 :(得分:2)

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

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

答案 3 :(得分:0)

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

因此,其他选择是:

将构造函数声明为private(以便您不能从类继承),但不提供定义:

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