其他方式禁止某些 C++类构造除了将构造函数声明为私有之外?

发布于 2024-12-03 01:10:04 字数 388 浏览 0 评论 0原文

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

class A {
};

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

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

Say I have a class with some const reference member variable and I would like to forbid a certain type of construction. So I would declare the according constructor private. Of course, a constructor must initialise all const reference member variables of the class. Doing so, however, results in odd looking code:

class A {
};

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

Is there another way to prohibit a certain construction type except than declaring the constructor private? I do not want to let the compiler write a constructor for me.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

看透却不说透 2024-12-10 01:10:04

简单地说,不要定义这个:

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

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

现在有趣的部分

您还可以有选择地禁用选定类型的构造函数,这使得删除更有趣。考虑到这一点,

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 创建对象,幸运的是或不幸的是,它可以隐式转换为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&)'

Simply don't define this:

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

That is, the following should do what you want to do:

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

The idea is if you've defined a constructor that takes parameter(s), then the default constructor is not generated by the compiler. That means, instances of the above class cannot be default created!

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

C++11 solution

In C++11, you can explicity tell the compiler not to generate a particular constructor as:

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

     B() = delete;      //disable
};

Not only that. There is more to it, as explained below:

Now the interesting part

You can also selectively disable constructor(s) for selected types which makes delete more interesting. Consider this,

struct A
{
       A (int) {}
};

Object of this class can be created not only with int argument, but any type which implicitly converts to int. For example,

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

Now suppose, for whatever reason, I don't want the users of class A to create objects with char or class B , which fortunately or unfortunately can implicitly convert to int, then you can disable them as:

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

Now here you go:

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

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

Online Demo : http://ideone.com/EQl5R

The error messages are very clear:

prog.cpp:9:5: error: deleted function 'A::A(char)'
prog.cpp:10:5: error: deleted function 'A::A(const B&)'

帝王念 2024-12-10 01:10:04

把它留下吧。一旦提供自定义构造函数,就不会自动生成其他构造函数(复制构造函数除外)。

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

Just leave it out. As soon as you provide a custom constructor, no other constructor is auto-generated (except for a copy constructor).

If you want to forbid any construction – ending up with a class that has only static members – you can simply declare the constructor as private, and not define it. Such a class is very rarely useful in C++ (since you cannot create instances of it); the only purpose that I can think of is to implement trait classes:

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();

However, this is extremely uncommon: trait classes are abundant in C++ but they never declare their constructors as private, it’s just assumed that everybody knows not to instantiate them.

凉城 2024-12-10 01:10:04

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

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

I'll post the C++11 solution: delete the constructor.

class B {
  B() = delete;
  B(const A& a): host(a) {}
private:
  const A& host;
};
疯狂的代价 2024-12-10 01:10:04

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

As Konrad Rudolph sayd: as soon you provide a custom constructor, no other constructor is auto-generated (except for a copy constructor).

Therefore, other options are:

Declare the constructor private (so that you can't inherit from your class), but do not provide a definition:

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

Or in C++11, as R. Martinho Fernandes says:

class B {
public:
  B() = delete;
  B(const A& a): host(a) {}
private:
  const A& host;
};
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文