C++ 链接类静态变量而不包含整个类声明
假设我有一个源文件a.cpp:C++ 链接类静态变量而不包含整个类声明,c++,static,C++,Static,假设我有一个源文件a.cpp: #include<string> struct A { static const std::string a; static const std::string b; static const std::string c; }; const std::string A::a{"1"}; const std::string A::b{"2"}; const std::string A::c{"3"}; 这当然会起作用,但我希望避免包含
#include<string>
struct A {
static const std::string a;
static const std::string b;
static const std::string c;
};
const std::string A::a{"1"};
const std::string A::b{"2"};
const std::string A::c{"3"};
这当然会起作用,但我希望避免包含类声明,因为在我的例子中,A
是巨大的,并且具有繁琐的依赖关系
理想的情况下,我想要像
struct A;
external const std::string A::m;
但这会产生不完整的类型错误
可以通过其他非类全局变量进行链接
const std::string A::b{"2"};
const std::string* bptr{&A::b};
并在另一个源文件中将其声明为
extern const std::string* bptr;
这是正确的方法,但对我来说有点难看,因为需要引入冗余实体
另一个对我有用的技巧
struct A {
static const std::string b;
};
int main(){
std::cout << A::b << "\n";
return 0;
}
结构A{
静态常量std::字符串b;
};
int main(){
std::cout您在结尾展示的技巧可能是最糟糕的攻击,并且可能有一天会适得其反-因为它“隐藏”了另一个定义。这里没有“中间”(除了许多“攻击”),要么使类定义整体出现,要么将字符串定义从类中移除 它看起来不错,但很粗糙,甚至对私人会员也有效。它合法吗?
取决于上下文,如果一个第三个单元有可能被拉进来,那么你将回到最初的问题。它为私人工作的原因是它的另一个错误,因此从一开始就不是私人的。
< P>从上一个角度来看,最后一个变体把我看作某种黑魔法。但是我想它为什么工作得越多,我就越认为它。这几乎是正确的 一个定义规则。实际上有两个实体需要查看:一个字符串和一个类 字符串完全遵循一个定义规则。这让我很困惑。它与在不同的源中声明相同的全局变量没有太大区别。如果有其他引用相同的定义,链接器就不会有任何问题。这种双重声明除了提供对同一定义的两个引用之外没有任何特殊作用。而且,yes、 链接器不关心不同声明的不同访问修饰符 该类违反了一条定义规则。在提供的示例中,这种差异不能破坏任何东西。但是,将非静态成员添加到某个定义中,并尝试在具有不同类定义的转换单元之间移动对象,这将导致失败 从技术上讲,维持这两个定义并不困难,但无论如何,最好避免而且,我可能会坚持昆汀建议的解决方案,通过附加函数提供访问。如果
A
中只有静态成员变量,那么您可以将A
从结构更改为命名空间(将struct
更改为namespace
,并去掉所有变量名前面的static
),然后可以拆分“A.h”放入多个头文件,以便只包含所需的部分。所有变量的定义可以在一个.CPP文件中,也可以在多个文件中拆分。如果使用完整的类定义(尽可能大),将它放在一个头文件中,该头文件包含在一个源文件中,就像您显示的第一个main
源文件一样简单,然后测量使用包含的头文件编译主源文件的时间,它是否值得注意?如果不是,那么您的类就足够小,可以按其应该的方式放入自己的头文件中,并且您不必这样做担心“黑客”和破坏。第一个问题是,你真的需要这样一个庞大的类,依赖繁琐吗?好的班级遵循一个实体一责任原则。如果你是这样的话,你可能还想考虑pIMPL成语来完全将类API与所有的实现细节分开。也许(我们不知道细节)这将使你的头独立于这些繁琐的依赖关系。你可以创建<代码> STD::String const和GETBSTRIGHORFEMA();<代码>,在代码> .CPP</代码>中定义它,在那里知道类。注意C++中的模块正在进行的工作,否则,它们将需要时间来规范化。(或者它们是用c++20编写的?)您所拥有的不是C++中的模块,有些程序员,它不是一个定义,而是一个声明。可以有多个声明。不仅有时间,还有一些循环依赖关系,我不想解决。Daniel Langr,这不是设计时间。那个巨大的类已经被写入了。目前进行重构。昆汀,这可能是一个很好的解决方法,谢谢。User463035818,好的,翻译单元/源代码。我试过gcc 5.4。它没有任何特殊的力量链接。但我给你一个适得其反的警告。应该已经编译。我想你意识到主要的问题是你将有不同的定义,这是一个维护噩梦。您现在遇到了2不兼容二进制的情况,因此代码另一部分中的逻辑强制转换可能会崩溃。可能还有其他问题。因此,这是您不想走下去的路径。“是否合法”不“依赖”。它违反了ODR(头版本)。
struct A {
static const std::string b;
};
int main(){
std::cout << A::b << "\n";
return 0;
}