2013-05-20 18 views
1

我一直在試圖去'pimpl'的習語中,但是我無法得到想要編譯的東西。編譯一個pimpl習語代碼的問題

在Linux Mint的使用g ++ 4.6.3 v我得到以下錯誤:

$ g++ main.cc 
/tmp/ccXQ9X9O.o: In function `main': 
main.cc:(.text+0xd7): undefined reference to `Person::Person(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, int)' 
collect2: ld returned 1 exit status 

這是我的代碼:

person.hh

#ifndef PERSON_HH 
#define PERSON_HH 

#include <tr1/memory> 
#include <string> 

class Person 
{ 
    private: 
    class PersonImpl; 
    std::tr1::shared_ptr<PersonImpl> pImpl; 

    public: 
    Person(const std::string& name, int age=0); 

    ~Person(); 

    const std::string& get_name() const; 

    int get_age() const; 
}; 

#endif 

person.cc

#include <string> 
#include "person.hh" 

class Person::PersonImpl 
{ 
    public: 
    std::string name; 
    int age; 

    PersonImpl(const std::string& n, int a) : name(n), age(a) {} 
}; 

Person::Person(const std::string& name, int age) : pImpl(new PersonImpl(name, age)) {} 

Person::~Person() {} 

const std::string& Person::get_name() const { return pImpl->name; } 

int Person::get_age() const { return pImpl->age; } 

main.cc

#include <iostream> 
#include "person.hh" 

int main() 
{ 
    const std::string name = "foo"; 
    Person p(name, 50); 

    return 0; 
} 

除了代碼錯誤,你能不能請告知方法,我已經採取了模仿「平普爾」成語?這符合它嗎?

回答

4

該問題似乎是由於您的person.cc文件未被鏈接。您可能需要調整項目配置才能解決此問題。

Apart from the code mistakes, could you please advise on the approach I've taken to mimicking a 'pimpl' idiom? Does this conform to it?

我會建議使用unique_ptr而非shared_ptr,因爲PersonImpl執行對象由Person對象專屬於:

class Person 
{ 
private: 
    class PersonImpl; 
    std::tr1::unique_ptr<PersonImpl> pImpl; 
//   ^^^^^^^^^^ 
    // ... 
}; 

除了這個,你應該利用constructor initialization lists到initalize的pImpl數據成員:

Person::Person(const std::string& name, int age) 
    : pImpl(new PersonImpl(name, age)) 
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
{ 
} 
+0

感謝unique_ptr建議和這個特殊情況下的初始化列表,我在解決鏈接問題時發現了一些其他的問題。 – Nobilis

+1

@Nobilis:很高興幫助:) –

3

您需要用構建兩個源文件。這既可以做只是把兩個源文件的命令行:

$ g++ -Wall -g main.cc person.cc 

或者通過編譯逐一到目標文件,然後將它們連接在一起

$ g++ -Wall -g main.cc -c 
$ g++ -Wall -g person.cc -c 
$ g++ main.o person.o 

-c選項告訴GCC創建一個目標文件而不是嘗試鏈接。 -Wall啓用了更多的警告,這總是一個好主意(它們可以指示一些意想不到的行爲),並且-g告訴GCC生成調試信息(調試時很好,特別是如果需要調試器,因爲調試信息包含符號名稱)。

+0

感謝的是,不能相信我被這樣的初學者的錯誤抓出來,用打交道時,包括守衛我通常確保我包括所有在我的生成文件中的.cc文件,但只是試圖在命令行上實際運行它。多麼尷尬:) – Nobilis

3

You get getti鏈接器錯誤,而不是編譯錯誤。連接時,必須列出所有你的程序的源文件:

g++ main.cc person.cc 

或者,只編譯,使用-c

g++ -c main.cc 

編輯

此外,您Person構造函數是錯誤的。你認爲pImpl是一個函數,我假設你想要啓動它。你需要使用mem-初始化器列表的語法爲:

Person::Person(const std::string& name, int age) 
    : pImpl(new PersonImpl(name, age)); 
{} 
+0

是的,一個非常初學者的錯誤,對於更大的項目我確保將所有源文件包含在Makefile中,但忘記了在這裏做。也感謝您的初始化列表評論,知道的好東西。 – Nobilis