【问题标题】:How to prevent a C++ compiler from creating any default class member?如何防止 C++ 编译器创建任何默认类成员?
【发布时间】:2017-07-20 13:29:55
【问题描述】:

我正在设计一些类来访问和控制微控制器的外围设备(adc、端口、usart 等)。该设备只有几个(在某些情况下只有一个)每个外围设备的实例,所以我决定将每个外围设备表示为一个单态类。我的一个类的定义和用法是这样的:

usart.h

class usart {
public:
    static void init() { /* initialize the peripheral */ } 
    static char read() { /* read a char from the input buffer */ }
    static void write(char ch) { /* write a char to the output buffer */ }
    // ... more member functions
};

ma​​in1.cpp

#include "usart.h"

int main()
{
    usart::init();

    char data;
    while (true) {
        data = usart::read();
        usart::write(data);
    }

}

但是上面定义 usart 类的方式并没有禁止用户做这样的事情:

ma​​in2.cpp

#include "usart.h"

int main() 
{
    // I don't want object construction
    usart serial1;
    usart serial2;

    // neither assignment
    serial1 = serial2;

    // two objects representing the same hardware resource
    // I don't want that
    serial1.init();
    serial2.write('r');
}

我知道从 C++11 开始我可以使用 delete 关键字来阻止编译器创建默认构造函数和函数,但我不知道编译器创建的这些默认值到底是什么。有复制构造函数、复制赋值、移动语义重载等。我需要在我的类上放置多少删除(以及在哪些函数和构造函数中)?

更新:我知道我可以(也许应该)使用命名空间而不是类,但我担心以后我需要将这些类(或命名空间)作为模板参数传递。 AFAIK 无法使用命名空间作为模板参数,因为我选择使用具有静态成员的类而不是命名空间。

【问题讨论】:

  • ~usart() = delete; 现在无法创建实例。
  • 如果您打算没有实例 - 为什么要使用类?只需使用带有函数的命名空间。
  • 简单,不要滥用类。 namespace usart { }.
  • 雅格尼。我已经处理了几种“单例”硬件(fpga、cpld、usart 等)恕我直言,您现在可以付出任何努力来防止不熟悉您的代码和系统的人在未来。他们犯的任何错误都不是你的错。让你的类使用简单、直接、易读。在我的嵌入式软件工作中,静态方法属性很少甚至不存在,静态数据属性仅限于“唯一 ID”计数器。我再说一遍,亚格尼。
  • 其实我收回了。仅仅禁用一个析构函数仍然可以让一个人写usart* p = new usart();(然后泄漏实例,因为他们无法销毁它)。但是,禁用默认构造函数(并且不提供任何其他构造函数)可以解决问题:usart() = delete; 是的,编译器将生成复制构造函数等 - 但在复制实例之前,您需要创建一个实例来复制 来自,并且不会有构造函数。

标签: c++ c++11 design-patterns monostate


【解决方案1】:
struct cannot_exist {
  cannot_exist()=delete;
  ~cannot_exist()=delete;
  cannot_exist(cannot_exist const&)=delete;
  cannot_exist(cannot_exist &&)=delete;
  cannot_exist& operator=(cannot_exist const&)=delete;
  cannot_exist& operator=(cannot_exist &&)=delete;
};

这是一个类,其中 C++ 为您生成的每个成员都被显式删除。 (你可以用更少的钱来做到这一点,但我认为这一点不那么明确)。

简单地从cannot_exist 继承,并且......你的类的实例不能存在,也不会有编译器自动定义的任何成员函数。尝试调用它们会产生编译器错误。

但是,一旦您有一个不存在的类,请考虑使用namespace

class usart:cannot_exist {
public:
  static void init() { /* initialize the peripheral */ } 
  static char read() { /* read a char from the input buffer */ }
  static void write(char ch) { /* write a char to the output buffer */ }
  // ... more member functions
};

namespace usart {
  static void init() { /* initialize the peripheral */ } 
  static char read() { /* read a char from the input buffer */ }
  static void write(char ch) { /* write a char to the output buffer */ }
  // ... more member functions
};

【讨论】:

    【解决方案2】:

    我会尝试这两种方法

    1. 在类中声明一个纯虚函数。这使得类是纯虚拟的,所以它不能被实例化。

    2. 将默认构造函数声明为私有成员函数。这样,没有外部类方法可以访问构造函数。

    【讨论】:

      猜你喜欢
      • 2019-11-08
      • 1970-01-01
      • 1970-01-01
      • 2016-10-14
      • 1970-01-01
      • 2010-11-19
      • 2013-01-24
      • 1970-01-01
      相关资源
      最近更新 更多