[英]Is it possible to define classes with same name in same namespace but in different nested projects?
我在 Eclipse 有一个大项目,其中包含多个嵌套项目。 这些嵌套项目中的每一个都位于一个单独的文件夹中,并单独编译和链接。 最后,它们每个都输出一个单独的 static 库。 然后很少有可执行文件与这些 static 库链接。 在其中两个项目中,我有两个具有相同名称和相同构造函数 arguments 的类,但它们具有不同的实现和不同的额外成员。 两个类都在同一个命名空间中。 编译每个项目后,我使用他们为单独的可执行文件创建的 static 库。 每个可执行文件都与正确的 class 链接,它们不会混合实现。 一切似乎都很好。
问题是当我编译其中一个类时,编译器给我一个错误,我没有初始化一些成员变量,这些成员变量实际上属于另一个 class。 在编译期间,这些类不能相互访问——它们不包含另一个类,或者它们不包含标题,然后包含另一个。 它们位于不同的项目中,位于不同的文件夹中,并且分别编译。 那么,在编译第一个 class 时,编译器如何以某种方式查找第二个 class 的定义并给我一个错误,即我没有从中初始化成员? Since I am using Eclipse and my projects' structure is like this: Main C++ Project (which is not compiled) holds the other C++ projects as nested projects (which are compiled separately) inside it - is it possible that this is something related to Eclipse ?
我是否违反了单一定义规则,因为我的类在单独的项目中并且它们在单独的编译中编译,只有一些常见的 header 文件并且它们之间没有其他连接? 如果是这样,编译器怎么可能捕捉到这样的问题,但它仍然能够获得正确的 class 定义? 因为可以肯定它做对了,一切正常。
所以我的问题是编译器给我的警告,因为我必须在发送代码之前清除所有编译警告。 代码本身工作正常。
此致
===评论后更新===
首先,对不清楚的地方表示歉意。 这是整个项目结构的图像(我显然已经更改了名称:)):
我有 MainProject 项目,它充当其他项目的容器。 我不建造它。 在nested1中,我有制作 static 库的项目,然后我将其与 Executable1 和 Executable2 链接。 在嵌套 2 中,我有其他项目再次制作static库,然后我将其与 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 仅使用 static 库 StaticLib1 nested1 。
没有一个可执行文件链接到 StaticLib5 和 StaticLib9。 此外,在链接可执行文件期间我没有收到错误,在编译任何 MyFooBar 类时都会收到警告。 警告说:
Member memDiff2 was not initialized in this constructor
这两个类唯一可能共有的是一个 header,其中我有一个 class 前向声明和一些 typedef,我不在 class 本身中使用它们。
class MyFooBar;
typedef ListWidget* MyFooBarPtr;
typedef std::vector< MyFooBarPtr > MyFooBarVec;
typedef MyFooBarVec* MyFooBarVecPtr;
C++ 中有一个定义规则,您不能将类/函数定义两次。 更不用说定义不同的情况了。
话虽如此,还有一些隔离规则允许您绕过一个定义规则。 比如说,你有两个同名的类,但它们只在两个不同的.cpp 文件中定义和使用,那么一切都应该工作......
更新:它可能会编译,但它会这样做,因为 linker 做得不好。 如果定义不匹配,它将无法正常工作。 但是当您有项目级别分离时,它确实有效,即在不同的共享库文件aka.dll - 需要动态库级别分离,.cpp 或 static 库分离级别不够。 感谢@fdan 和@FrancisCugler。
基本上,只要有任何项目以某种方式使用这两种定义 - 以免存在强大的编译边界 - 它违反了一个定义规则并且无法正确编译。
PS为什么甚至有两个同名的类? 这是一个极好的错误来源。 如果你想在不同的架构或操作系统系统之间有可移植的代码,你可以使用#ifdef 从构建中删除不合适的 class 版本。
让我们考虑一下编译器在幕后做了什么:我们有两个模块或翻译单元:模块 A 和 B。
在编译期间,我们将有以下内容:
Module A: namespace::class_name == foo::bar
Module B: namespace::class_name == foo::bar
在将源代码编译为 object 文件期间,这些文件将按照您的说明单独编译。 这里的问题不在于编译器。
当它使用所有 object 代码或翻译单元并尝试将所有内容链接在一起以构建单个可执行文件时,就会出现问题。
这是您最终遇到违反单一定义规则的命名或符号解析冲突的时候。 问题出现在 linker 内。
然而,一些在集成开发环境(如 Visual Studio)中构建的编译器可能有一些编译器标志,这些标志将“向前看”,可以说在编译完成之前是否会发生任何可能的冲突,这可能会产生编译时警告甚至甚至在您到达 linker 之前出现错误。
我建议更改类的名称或名称空间名称,但是将名称空间名称保留在类名称之上会更方便,因为这是代表您的代码库的名称空间。
如果由于某种原因您需要将 class 保留为相同的名称,那么它们可能是另一种选择,即包含一个中间的内部嵌套命名空间名称来解决这种命名冲突以减少歧义。
例如:
Module A: namespace::namespace::class_name = foo::ver_1::bar
Module B: namespace::namespace::class_name = foo::ver_2::bar
然后,只要您不使用以下指令,内部嵌套命名空间就会防止这种命名冲突:
#using namespace foo::ver_1;
#using namespace foo::ver_2;
在同一可见范围内!
首先,感谢您的帮助。 问题似乎出在 QNX Momentics IDE 本身。 如果我从命令行构建项目,则不会打印任何警告。 如果我从nested1 构建第一个MyFooBar,然后从nested2构建一个项目,然后从nested2 构建第二个MyFooBar ,我会收到此警告。 如果我构建第一个 MyFooBar,然后从nested1构建其他几个项目,然后是第二个 MyFooBar,则没有此类警告。 在任何一种情况下,构建都很好,一切都按预期工作。
最好的问候,艾哈迈德
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.