Другой способ запретить определенную конструкцию класса C ++, кроме как объявление конструктора частным?
-
26-10-2019 - |
Вопрос
Скажи, что у меня есть класс с некоторыми Конст Ссылка переменная участника, и я хотел бы запретить определенный тип строительства. Поэтому я бы объявил о конструкторе частный. Анкет Конечно, конструктор должен инициализировать все Конст Ссылка переменные члена класса. Это, однако, приводит к нечетному коду:
class A {
};
class B {
B(const A& a): host(a) {}
private:
B():host(A()) {} // This is ugly and not needed !!
const A& host;
};
Есть ли другой способ запретить определенный тип строительства, за исключением того, что объявление конструктора частным? Я не хочу позволять компилятору написать для меня конструктор.
Решение
Просто не определяйте это:
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
создавать объекты с char
или же class 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 &)'
Другие советы
Просто оставьте это. Как только вы предоставите пользовательский конструктор, ни один другой конструктор не генерируется автоматическим (за исключением конструктора копирования).
Если вы хотите запретить Любые Строительство - заканчивается классом, в котором есть только статические участники - вы можете просто объявить конструктор как частный, а не определять Это. Такой класс очень редко полезен в 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
, просто предполагается, что все знают, что не могут их создавать.
Я опубликую решение C ++ 11: Удалить конструктор.
class B {
B() = delete;
B(const A& a): host(a) {}
private:
const A& host;
};
Как Конрад Рудольф Сэйд: как только вы предоставите пользовательский конструктор, ни один другой конструктор не генерируется (за исключением конструктора копирования).
Следовательно, другие варианты:
Объявить конструктор частным (чтобы вы не могли унаследовать от своего класса), но не дайте определения:
class B {
public:
B(const A& a): host(a) {}
private:
B(); // not implemented!
const A& host;
};
Или в C ++ 11, как говорит Р. Мартинью Фернандес:
class B {
public:
B() = delete;
B(const A& a): host(a) {}
private:
const A& host;
};