Я разрабатываю несколько классов для доступа и управления периферийными устройствами микроконтроллера (АЦП, порт, USB и т. Д.). Устройство имеет всего несколько (в некоторых случаях только один) экземпляров каждого периферийного устройства, поэтому я решил представить каждое периферийное устройство в виде класса с одним состоянием. Определение и использование одного из моих классов будет примерно таким:
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
};
main1.cpp
#include "usart.h"
int main()
{
usart::init();
char data;
while (true) {
data = usart::read();
usart::write(data);
}
}
Но способ, которым класс usart определен выше, не запрещает пользователю делать что-то вроде этого:
main2.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 я могу использовать удалять ключевое слово, чтобы предотвратить создание компилятором конструкторов и функций по умолчанию, но я не знаю точно, что это за настройки по умолчанию, которые создает компилятор. Существуют конструкторы копирования, назначения копирования, перегрузки семантики перемещения и т. Д. Сколько удалятьs мне нужно поставить на мой класс (и в каких функциях и конструкторах)?
ОбновитьЯ знаю, что могу (и, возможно, должен) использовать пространства имен вместо классов, но, боюсь, позже мне нужно будет передать эти классы (или пространства имен) в качестве аргументов шаблона. AFAIK: невозможно использовать пространства имен в качестве аргументов шаблона, из-за этого я решил использовать классы со статическими членами вместо пространств имен.
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
};
Я бы попробовал эти два способа
Объявите чисто виртуальную функцию в классе. Это делает класс чисто виртуальным, поэтому его нельзя создать.
Объявите конструктор по умолчанию как закрытую функцию-член. Таким образом, метод внешнего класса не может получить доступ к конструктору.