编译pimpl成语代码的问题

时间:2013-05-20 13:16:45

标签: c++ pimpl-idiom

我一直在试图去找一个'pimpl'成语,但是我无法得到编译的东西。

在Linux Mint上使用g ++ v.6.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; }

main.cc

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

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

    return 0;
}

除了代码错误之外,您能否就我采用的模仿'pimpl'成语的方法提出建议?这符合它吗?

3 个答案:

答案 0 :(得分:4)

问题似乎是因为您的person.cc文件未被链接。您可能需要调整项目配置以解决此问题。

  

除了代码错误之外,您能否就我采用的模仿'pimpl'成语的方法提出建议?这符合它吗?

我建议使用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))
//  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
{
}

答案 1 :(得分: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生成调试信息(调试时很好,特别是如果需要调试器作为调试信息包括符号名称。)

答案 2 :(得分:3)

您收到链接器错误,而不是编译错误。链接时,您必须列出所有程序的源文件:

g++ main.cc person.cc

或者,要仅编译,请使用-c

g++ -c main.cc

修改

此外,您Person构造函数是错误的。您将pImpl视为一个函数,我假设您想要将其初始化。您需要使用mem-initialiser-list语法:

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