Почему следующий код не дает мне ошибку компоновщика дубликатов символов для Impl?
Я столкнулся с этой проблемой в некотором унаследованном коде, и для простоты я воссоздаю более короткую версию.
У меня есть два класса, Foo и Bar, каждый из которых определяет разные версии одной и той же структуры (Impl) в каждом из своих файлов .cpp. Таким образом, каждый из Foo.cpp и Bar.cpp имеет одноименное определение Impl, но у каждого своя реализация встроенного конструктора.
И Foo, и Bar имеют переменную-член типа Impl, и каждый форвард объявляет Impl в своем файле .h.
Foo.cpp сообщает экземпляр Bar внутри своего конструктора. Что интересно, то, что создается, зависит от порядка связывания файлов.
Итак, эта команда компиляции:
g++ -o a.out main.cpp Bar.cpp Foo.cpp
приводит к выводу:
==> main()
Bar.cpp's Impl::Impl()
Bar.cpp's Impl::Impl()
<== main()
И эта команда:
g++ -o a.out main.cpp Foo.cpp Bar.cpp
приводит к выводу:
==> main()
Foo.cpp's Impl::Impl()
Foo.cpp's Impl::Impl()
<== main()
Я пробовал это с gcc 4.1.2, Visual Studio 2008 и Green Hills Multi 4.2.4, и все они дают одинаковый результат.
foo.h
#ifndef FOO_H
struct Impl;
class Bar;
class Foo
{
public:
Foo();
~Foo();
private:
Impl* p;
Bar* bar;
};
#endif
foo.cpp
#include <iostream>
#include "Foo.h"
#include "Bar.h"
struct Impl
{
Impl()
{
std::cout << "Foo.cpp's Impl::Impl()" << std::endl;
}
};
Foo::Foo()
: p(new Impl),
bar(new Bar)
{
}
Foo::~Foo()
{
delete p;
delete bar;
}
bar.h
#ifndef BAR_H
#define BAR_H
struct Impl;
class Bar
{
public:
Bar();
~Bar();
private:
Impl* p;
};
#endif
Bar.cpp
#include <iostream>
#include "Bar.h"
struct Impl
{
Impl()
{
std::cout << "Bar.cpp's Impl::Impl()" << std::endl;
}
};
Bar::Bar()
: p(new Impl)
{
}
Bar::~Bar()
{
delete p;
}
main.cpp
#include <iostream>
#include "Foo.h"
int main (int argc, char const *argv[])
{
std::cout << "==> main()" << std::endl;
Foo* f = new Foo();
std::cout << "<== main()" << std::endl;
return 0;
}