Gibt es eine andere Möglichkeit, eine bestimmte C++-Klassenkonstruktion zu verbieten, als den Konstruktor als privat zu deklarieren?

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

  •  26-10-2019
  •  | 
  •  

Frage

Angenommen, ich habe mit einigen einen Kurs const-Referenz Mitgliedsvariable und ich möchte eine bestimmte Art der Konstruktion verbieten.Also würde ich den entsprechenden Konstruktor deklarieren Privat.Natürlich muss ein Konstruktor alles initialisieren const-Referenz Mitgliedsvariablen der Klasse.Dies führt jedoch zu seltsam aussehendem Code:

class A {
};

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

Gibt es eine andere Möglichkeit, einen bestimmten Bautyp zu verbieten, als den Konstruktor als privat zu deklarieren?Ich möchte nicht, dass der Compiler einen Konstruktor für mich schreibt.

War es hilfreich?

Lösung

Definieren Sie das einfach nicht:

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

Das heißt, Folgendes sollte das tun, was Sie tun möchten:

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

Die Idee besteht darin, dass, wenn Sie einen Konstruktor definiert haben, der Parameter akzeptiert, der Standardkonstruktor nicht vom Compiler generiert wird.Das heißt, Instanzen der oben genannten Klasse kann nicht Sei Standard erstellt!

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

C++11-Lösung

In C++11 können Sie den Compiler explizit anweisen, keinen bestimmten Konstruktor zu generieren:

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

     B() = delete;      //disable
};

Nicht nur das.Es steckt noch mehr dahinter, wie unten erklärt:

Nun der interessante Teil

Sie können Konstruktoren auch selektiv deaktivieren ausgewählt Typen was macht delete interessanter.Bedenken Sie,

struct A
{
       A (int) {}
};

Objekte dieser Klasse können nicht nur mit erstellt werden int Argument, sondern jeder Typ, der implizit konvertiert wird int.Zum Beispiel,

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

Nehmen wir nun an, aus welchem ​​Grund auch immer, ich möchte die Benutzer der Klasse nicht haben A Objekte damit erstellen char oder class B , was glücklicherweise oder leider möglich ist implizit konvertieren zu int, dann können Sie sie wie folgt deaktivieren:

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

Jetzt geht es los:

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

Die Fehlermeldungen sind sehr klar:

prog.cpp:9:5:Fehler:gelöschte Funktion 'A::A(char)'
prog.cpp:10:5:Fehler:gelöschte Funktion 'A::A(const B&)'

Andere Tipps

Lass es einfach aus. Sobald Sie einen benutzerdefinierten Konstruktor zur Verfügung stellen, wird kein anderer Konstruktor automatisch generiert (mit Ausnahme eines Kopierkonstruktors).

Wenn Sie verbieten wollen irgendein Konstruktion - endet mit einer Klasse, die nur statische Mitglieder hat - Sie können einfach erklären der Konstruktor als privat und nicht definieren es. Eine solche Klasse ist in C ++ sehr selten nützlich (da Sie keine Instanzen davon erstellen können); Der einzige Zweck, den ich mir vorstellen kann, ist die Implementierung von Merkmalklassen:

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

Dies ist jedoch äußerst ungewöhnlich: Merkmalklassen sind in C ++ reichlich vorhanden, aber sie erklären ihre Konstrukteure nie als private, Es wird nur angenommen, dass jeder weiß, dass er sie nicht instanziiert.

Ich werde die C ++ 11 -Lösung veröffentlichen: löschen der Konstruktor.

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

Wie Konrad Rudolph Sayd: Sobald Sie einen benutzerdefinierten Konstruktor zur Verfügung stellen, wird kein anderer Konstruktor automatisch generiert (mit Ausnahme eines Kopierkonstruktors).

Daher sind andere Optionen:

Deklarieren Sie den Konstruktor privat (damit Sie nicht von Ihrer Klasse erben können), geben aber keine Definition an:

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

Oder in C ++ 11, wie R. Martinho Fernandes sagt:

class B {
public:
  B() = delete;
  B(const A& a): host(a) {}
private:
  const A& host;
};
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top