是否可以在相同的命名空间但在不同的嵌套项目中定义具有相同名称的 类 ?

Is it possible to define classes with same name in same namespace but in different nested projects?

我在Eclipse 中有一个大项目,其中包含多个嵌套项目。这些嵌套项目中的每一个都在一个单独的文件夹中,并单独编译和 linked。最后,他们每个人都输出一个单独的静态库。然后很少有可执行文件针对这些静态库进行 linked。在其中两个项目中,我有两个具有相同名称和相同构造函数参数的 classes,但它们具有不同的实现和不同的额外成员。两个 classes 都在同一个命名空间中。在我编译每个项目后,我使用他们为单独的可执行文件创建的静态库。每个可执行文件都是 link 针对正确的 class 编辑的,它们不会混合实现。似乎一切正常。

问题是当我编译其中一个class时,编译器报错说我没有初始化一些成员变量,这些成员变量实际上属于另一个class。在编译期间,这些 classes 无法相互访问 - 它们不包含另一个,或者它们不包含 headers,后者又包含另一个。它们在不同的项目中,在不同的文件夹中,并且是单独编译的。那么在编译第一个 class 时,编译器怎么可能会以某种方式查找第二个 class 的定义,并给我一个错误,说我没有从它初始化一个成员?因为我使用的是 Eclipse 并且我的项目结构是这样的:Main C++ Project(未编译)将其他 C++ 项目作为嵌套项目(单独编译)保存在其中 - 这可能与 Eclipse 相关?

我是否违反了一个定义规则,因为我的 classes 在不同的项目中并且它们是在不同的编译中编译的,只有一些共同的 header 文件并且它们之间没有其他联系?如果是这样,编译器怎么可能捕捉到这样的问题但仍然能够获得正确的 class 定义?因为肯定它做对了,一切正常。

所以我的问题是编译器给我的警告,因为我必须在发布代码之前清除所有编译警告。代码本身工作正常。

此致

===评论后更新===

首先,很抱歉不清楚。 这是整个项目结构的图像(我显然已经更改了名称:)):

The structure of my project

我有 MainProject 项目,它充当其他项目的容器。我不建造它。在 nested1 中,我有制作静态库的项目,然后 link 使用 Executable1 和 Executable2。在 nested2 中,我还有其他项目再次制作静态库,然后我 link 使用 Executable3。

我在 nested1 和 nested2 中都有 MyFooBar class。这是他们两个的代码

// nested1/StaticLib5/MyFooBar.hpp
namespace foo
{
    namespace bar
    {
        class MyFooBar : public FooBar
        {
            public:
                   MyFooBar(int a, int b, double c);
                   // Getters and Setters
                   // Other user-defined functions
            private:
                   int memA;
                   int memB;
                   double memC;
                   int memDiff1;
        };
    }
}
// nested2/StaticLib9/MyFooBar.hpp
namespace foo
{
    namespace bar
    {
        class MyFooBar : public FooBar
        {
            public:
                   MyFooBar(int a, int b, double c);
                   // Getters and Setters
                   // Other user-defined functions
            private:
                   int memA;
                   int memB;
                   double memC;
                   int memDiff2;
                   char memDiff3;

        };
    }
}
// nested1/StaticLib5/MyFooBar.cpp
namespace foo
{
    namespace bar
    {
        MyFooBar::MyFooBar(int a, int b, double c) :
        memA{a}, memB{b}, memC{c}, memDiff1{0}
        {
        }         
    }
}
// nested2/StaticLib9/MyFooBar.cpp
namespace foo
{
    namespace bar
    {
        MyFooBar::MyFooBar(int a, int b, double c) :
        memA{a}, memB{b}, memC{c}, memDiff2{0}, memDiff3{0}
        {
        }         
    }
}

Executable1 和 Executable2 不使用 nested2 中的任何库。 Executable3 使用唯一的静态库StaticLib1 nested1

没有可执行文件被link编辑到 StaticLib5 和 StaticLib9。此外,在 linking 可执行文件期间我没有收到错误,在编译任何 MyFooBar classes 时收到警告。警告说:

Member memDiff2 was not initialized in this constructor

两个 classes 唯一可能共同的是一个 header,其中我有一个 class 前向声明和一些我不使用的类型定义class 本身。

class MyFooBar;
typedef ListWidget* MyFooBarPtr;
typedef std::vector< MyFooBarPtr > MyFooBarVec;
typedef MyFooBarVec* MyFooBarVecPtr;

C++ 中有一条定义规则,即不能将 classes/functions 定义两次。更不用说定义不同的情况了。

也就是说,还有隔离规则可以让你绕过单一定义规则。比如说,您有两个同名的 classes,但它们仅在两个不同的 .cpp 文件中定义和使用,那么一切都应该有效...

更新:它可能会编译,但它会编译,因为链接器做得不好。如果定义不匹配,它将无法正常工作。但是当你有项目级别分离时它确实有效,即在不同的共享库文件中,也就是 .dll - 需要动态库级别分离,.cpp 或静态库分离级别是不够的。感谢@fdan 和@FrancisCugler。

基本上,只要有任何项目以某种方式同时使用这两种定义——以免存在强大的编译边界——就是违反了一种定义规则而无法正确编译。

P.S。为什么甚至有两个 class 同名?这是错误的极好来源。如果你想在不同的体系结构或 OS 系统之间拥有可移植的代码,你可以使用 #ifdef 从构建中删除 class 的不合适版本。

让我们考虑一下编译器在幕后做了什么:我们有两个模块或翻译单元:模块 A 和 B。

在编译过程中我们会有以下内容:

Module A: namespace::class_name == foo::bar 
Module B: namespace::class_name == foo::bar

在将源代码编译成目标文件的过程中,正如您所说,这些文件将单独编译。这里的问题不在于编译器。

当它获取所有目标代码或翻译单元并尝试 link 将所有内容组合在一起以构建单个可执行文件时,就会出现问题。

这是当您最终遇到违反单一定义规则的命名或符号解析冲突时。正是在 link 人中出现了问题。

然而,一些在集成开发环境中构建的编译器,例如 Visual Studio 可能有一些编译器标志,这些标志将 "look ahead" 可以这么说,看看在编译完成之前是否可能发生任何可能的冲突这可能会在您进入 linker.

之前生成编译时警告甚至错误

我建议更改 class 的名称或名称space 的名称,但是将名称space 的名称保留在 [=37 之上会更方便=] 的名称,因为那是代表您的代码库的名称 space。

如果出于某种原因您需要将 class 保留为相同的名称,那么它们可能是另一种选择,即包含一个中间内部嵌套名称space 名称来解决此问题命名冲突以减少歧义。

例如:

Module A: namespace::namespace::class_name = foo::ver_1::bar
Module B: namespace::namespace::class_name = foo::ver_2::bar

然后内部嵌套名称space 将防止这种命名冲突,只要您不使用指令,例如:

#using namespace foo::ver_1;
#using namespace foo::ver_2;

同一可见范围内!

首先感谢您的帮助。问题似乎出在 QNX Momentics IDE 本身。如果我从命令行构建项目,则不会打印任何警告。如果我从 nested1 构建第一个 MyFooBar,然后从 nested2 构建一个项目,然后从 nested2 构建第二个 MyFooBar 我收到此警告。如果我构建第一个 MyFooBar,然后构建 nested1 中的其他几个项目,然后构建第二个 MyFooBar,则不会出现此类警告。在任何一种情况下,构建都很好,一切都按预期工作。

此致, 艾哈迈德