Другой способ запретить определенную конструкцию класса C ++, кроме как объявление конструктора частным?

StackOverflow https://stackoverflow.com/questions/7317530

  •  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;
};
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top