2013-02-22 64 views
7

my_test.h應該在C++頭文件中初始化一個const靜態變量嗎?

#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 

當使用該頭文件編譯CPP,錯誤發生'multiple definition of 'A::b'

  1. 爲什麼當我已經使用警衛宏?
  2. 爲什麼A::a不產生錯誤? (我不能在class A編寫代碼const static obj b={1,2}

回答

4

爲什麼當我已經使用警衛宏?

頁眉警衛只能防止的頭文件內容包含不止一次在同一translation unit不會在多個翻譯單元。

爲什麼A::a不具有錯誤消息(我不能寫在class A代碼const static obj b={1,2}

In-class initialization是由編譯器允許作爲靜態數據成員的特殊情況的const文字類型。你的例子之一是課堂上的初始化。

const A::b在包含標題的每個翻譯單元中定義相同的符號名稱,因此打破了one definition rule

您需要將定義移動到一個且只有一個源cpp文件,以便它只被定義一次。

+2

對於OP,作爲初學者,「你需要」是正確的。然而,作爲一個絕對的技術聲明它並不是,因爲類模板有一個ODR的例外。這意味着在技術上,如果真的需要它,可以在類模板中定義靜態常量,然後從任意專業化繼承。它有時被稱爲模板化的常量技巧。一個更實用的方法來避免一個實現文件(如果有的話)是通過一個內聯函數提供對常量的訪問(它可以將常量當作本地函數)。 – 2013-02-22 10:07:22

+0

@Alf:我同意你的評論說的。事實上,這是一個很好的信息。 – 2013-02-22 13:55:21

0

的問題是你的A::b定義不包含一個類型。要成爲一個有效的定義,它應該是:

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

這將擺脫編譯錯誤的,但你仍然會得到鏈接錯誤,如果你有一個以上的源文件這頭,因爲A::b會然後乘以定義。您應該將定義移動到.cpp文件中。

0

無論您是否有頭文件,將該初始化置於頭文件中意味着您將在包含該頭文件的每個源文件中獲得A::b的實例。因此鏈接器錯誤。

所以,一般來說,這是可能的,但不是一個好主意。

1

阿洛克已經回答了你的問題,但這裏有經驗的幾個簡單的規則,易於記憶的形式:

  1. 聲明中.h文件
  2. 定義去進去吧。CPP文件

因此,靜態成員必須宣佈.h文件,然後在.cpp文件中定義。在你的情況下,修復聲明的語法,然後將它們移動到「my_test.cpp」文件。

相關問題