2013-02-22 10 views
7

my_test.hUna variabile statica const può essere inizializzata in un file di intestazione C++?

#ifndef MY_TEST 
#define MY_TEST 

struct obj { 
    int x; 
    int y; 
}; 

class A { 
private: 
    const static int a=100; 
    const static obj b; 
}; 

const obj A::b={1,2}; 

#endif 

Quando si compila cpp utilizzando questo file di intestazione, un errore si verifica 'multiple definition of 'A::b'.

  1. perché è quando uso già macro di protezione?
  2. perché A::a non produce l'errore? (Non posso scrivere codice const static obj b={1,2} in class A)

risposta

4

perché è questo quando utilizzo già macro di protezione?

guardie Header impediscono solo l'inserimento del contenuto dei file di intestazione più di una volta nella stessa translation unit non su più unità di traduzione.

perché è A::a non ha il messaggio di errore (non posso scrivere codice const static obj b={1,2} in class A)

In-class initialization è consentito dal compilatore come un caso speciale per i membri dati statici di tipo letterale const. Il tuo esempio è l'inizializzazione in classe.

const A::b definisce lo stesso nome del simbolo in ogni unità di traduzione in cui l'intestazione viene incluso e quindi rompe il one definition rule.

È necessario spostare la definizione in uno e un solo file cpp sorgente in modo che venga definita solo una volta.

+2

Per l'OP, come principiante, "È necessario" è corretto. Tuttavia, come affermazione tecnica assoluta non lo è, perché esiste un'esclusione ODR per i modelli di classe. Ciò significa che tecnicamente, se ce n'è davvero bisogno, è possibile definire la costante statica in un modello di classe e quindi ereditare da una specializzazione arbitraria. A volte è conosciuto come il trucco costante basato su modelli. Un modo più pratico per evitare un file di implementazione, se lo si fa, è fornire l'accesso alla costante tramite una funzione inline (che può avere la costante come locale). ' –

+0

@ Alf: concordo su ciò che dice il tuo commento. In effetti questa è una buona informazione. –

0

Il problema è la tua definizione di A::b non contiene un tipo. Per essere una definizione valida, dovrebbe essere:

const obj A::b = {1, 2}; 

Questo permetterà di eliminare l'errore di compilazione, ma ci si può comunque errori del linker se si include questa intestazione in più di un file sorgente, perché A::b sarà moltiplicato definito allora. Dovresti spostare la definizione in un file .cpp.

0

Indipendentemente dal fatto che si disponga o meno di una protezione dell'intestazione, collocare tale inizializzazione in un file di intestazione significa che si otterrà un'istanza di A::b in ogni file di origine che include tale file di intestazione. Da qui l'errore del linker.

Quindi, in generale, è possibile, ma non è una buona idea.

1

Alok ha già risposto alla tua domanda, ma qui ci sono alcune semplici regole di pollice, in facile da memorizzare forma:

  1. dichiarazioni andare nel file .h
  2. Definizioni andare nel.il file cpp

Pertanto, i membri statici bisogno di essere dichiarato nel file h, e quindi definito nel file cpp. Nel tuo caso, correggi la sintassi delle dichiarazioni e spostale nel file "my_test.cpp".