C++/VS2005: определение одного и того же имени класса в двух разных файлах.cpp
Что-то вроде академического вопроса, но я столкнулся с этим, когда писал некоторые юнит-тесты.
Мой фреймворк для модульных тестов (UnitTest++) позволяет создавать структуры, служащие в качестве фиксаторов. Обычно они настраиваются для тестов в файле, поэтому я помещаю их в начало файла модульных тестов.
//Tests1.cpp
struct MyFixture { MyFixture() { ... do some setup things ...} };
TEST_FIXTURE(MyFixture, SomeTest)
{
...
}
//Tests2.cpp
struct MyFixture { MyFixture() { ... do some other setup things, different from Tests1}};
TEST_FIXTURE(MyFixture, SomeOtherTest)
{
...
}
Однако недавно я обнаружил (по крайней мере, с VS2005), что когда вы называете структуру фикстура, используя одно и то же имя (так что теперь две версии структуры существуют с одинаковым именем), одна из версий автоматически отбрасывается. Это довольно удивительно, потому что мой компилятор установлен на /W4 (самый высокий уровень предупреждения), и предупреждение не выдается. Я предполагаю, что это конфликт имен, и почему были изобретены пространства имен, но нужно ли мне оборачивать каждое из моих модульных тестовых устройств в отдельное пространство имен? Я просто хочу убедиться, что я не пропускаю что-то более фундаментальное.
Есть ли лучший способ исправить это - должно ли это происходить? Разве я не вижу ошибку повторяющихся символов или что-то?
3 ответа
Попробуйте поместить классы в анонимное пространство имен, вам может показаться, что это менее неприятно, чем необходимость создавать и именовать новое пространство имен для каждого файла.
У меня нет доступа к VS2005 и Cpp, но это может сработать..
//Tests1.cpp
namespace
{
struct MyFixture { MyFixture() { ... do some setup things ...} };
}
TEST_FIXTURE(MyFixture, SomeTest)
{
...
}
//Tests2.cpp
namespace
{
struct MyFixture { MyFixture() { ... do some other setup things, different from Tests1}};
}
TEST_FIXTURE(MyFixture, SomeOtherTest)
{
...
}
Компилятор работает только на одном модуле компиляции одновременно; это будет исходный файл и все, что оно включает. Так как ваши классы находятся в разных файлах, никаких конфликтов нет.
Компоновщик собирает все вместе, но он не знает об определениях классов, поэтому он также не видит конфликта.
Когда-то во времена Си, для компоновщика было достаточно распознать, что у вас две разные функции с одним и тем же именем, и сгенерировать сообщение об ошибке. Со встроенными функциями и шаблонами в C++ он больше не может этого делать - разные модули компиляции часто содержат дубликаты одной и той же функции, поэтому компоновщик просто предполагает, что они одинаковы.
В основном это является следствием того факта, что классы должны быть определены в заголовочных файлах, что приводит к избыточным определениям классов в каждом объектном файле. Таким образом, компоновщик, который может обрабатывать связи C++, должен сложить избыточные объявления классов и сделать вид, что класс был объявлен только один раз.
Компоновщик никак не может различить один класс, включенный в несколько объектов, и несколько классов с одинаковым именем в нескольких объектах.
Вы должны использовать пространства имен (или лучший язык), чтобы обойти это.