2013-05-20 2 views
1

Я пытаюсь пойти на идиому «pimpl», но я просто не могу получить эту черную вещь для компиляции.Проблемы с компиляцией кода идиомы pimpl

На Linux Mint с г ++ против 4.6.3 я получаю следующее сообщение об ошибке:.

$ 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; } 

основная.cc

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

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

    return 0; 
} 

Помимо кода ошибки, не могли бы вы посоветовать на подходе я принял к имитируя идиому «Pimpl»? Соответствует ли это этому?

ответ

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 чтобы инициализировать 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 в моем make-файле, но просто пытались запустить это в командной строке причинно. Как смущающе :) – Nobilis

3

You are getti ng ошибка компоновщика, а не ошибка компиляции. При компоновке, вы должны перечислить все исходные файлы вашей программы:

g++ main.cc person.cc 

Или компилировать только использовать -c:

g++ -c main.cc 

EDIT

Кроме того, вы Person конструктор неправильно ,Вы рассматриваете pImpl как функцию, где я предполагаю, что вы хотите ее инициализировать. Вы должны использовать синтаксис мем-инициализатора-лист для этого:

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

Да, ошибка самого новичка, по более крупным проектам я уверен, что я включаю все исходные файлы в Makefile, но забыл сделать это здесь. Также спасибо за комментарий к списку инициализатора, хорошо знать. – Nobilis

Смежные вопросы