Altro modo di vietare una certa costruzione di classe C ++, tranne che dichiarare il costruttore privato?

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

  •  26-10-2019
  •  | 
  •  

Domanda

Say Ho una classe con alcuni variabile riferimento const persona e desidero vietare un certo tipo di costruzione. Quindi mi sento di dichiarare il costruttore secondo privati ??. Naturalmente, un costruttore deve inizializzare tutte le riferimento const le variabili membro della classe. In questo modo, però, si traduce in codice strano guardare:

class A {
};

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

C'è un altro modo di vietare un certo tipo di costruzione, tranne che dichiarare il costruttore privato? Non voglio lasciare che il compilatore scrivere un costruttore per me.

È stato utile?

Soluzione

Semplicemente non definire questo:

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

Cioè, il seguente dovrebbe fare quello che si vuole fare:

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

L'idea è che se avete definito un costruttore che prende parametri (s), quindi il costruttore di default non viene generato dal compilatore. Ciò significa che, le istanze della classe sopra non possono essere default creato!

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

C ++ 11 soluzione

In C ++ 11, si può esplicitamente dire al compilatore non generare un costruttore particolare:

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

     B() = delete;      //disable
};

Non solo. C'è di più ad esso, come spiegato di seguito:

Ora la parte interessante

È anche possibile disabilitare selettivamente costruttore (s) per il tipi selezionati che rende delete più interessante. Considerate questo,

struct A
{
       A (int) {}
};

Oggetto di questa classe può essere creato non solo con l'argomento int, ma qualsiasi tipo che implicitamente convertiti int. Ad esempio,

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

Ora supponiamo che, per qualsiasi motivo, non voglio gli utenti della classe A di creare oggetti con char o class B, che per fortuna o purtroppo può implicitamente Converti in int, quindi è possibile disattivarli come:

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

Ora qui si va:

A a1(10);  //ok
A a2('x'); //error

B b; 
A a3(b); //error - assume (even if) b provides user-defined conversion to int

Demo Online: http://ideone.com/EQl5R

I messaggi di errore sono molto chiare:

prog.cpp: 9: 5: Errore: soppresso la funzione 'A :: A (char)'
prog.cpp: 10: 5: Errore: la funzione cancellato 'A :: A (const B &)'

Altri suggerimenti

Basta lasciarlo fuori. Non appena si fornisce un costruttore personalizzato, nessun altro costruttore è generato automaticamente (ad eccezione di un costruttore di copia).

Se si vuole proibire qualsiasi Costruzione - finire con una classe che ha solo i membri statici - si può semplicemente dichiarare al costruttore come privato, e non definire di esso. Tale Classe A è molto raramente utile in C ++ (poiché non è possibile creare istanze di esso); l'unico scopo che mi viene in mente è quello di implementare le classi tratto:

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

Tuttavia, questo è estremamente raro:. Classi tratto sono abbondanti in C ++ ma non hanno mai dichiarano i loro costruttori come private, è solo per scontato che tutti non sanno creare un'istanza di loro

vi posterò il C ++ 11 soluzione:. Elimina il costruttore

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

Come Konrad Rudolph sayd: non appena si fornisce un costruttore personalizzato, nessun altro costruttore è generato automaticamente (ad eccezione di un costruttore di copia)

.

Di conseguenza, le altre opzioni sono:

Dichiarare il costruttore privato (in modo che non si può ereditare dalla classe), ma non forniscono una definizione:

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

O in C ++ 11, come dice R. Martinho Fernandes:

class B {
public:
  B() = delete;
  B(const A& a): host(a) {}
private:
  const A& host;
};
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top