静态强制转换以访问静态常量类成员
Static Cast to access static const class member
所以昨天我在So上找不到以下问题的答案。这种情况来自我正在使用的一些源代码,但这里是MCVE来演示它
我在a.h中定义了一个类a,它只有一个静态常量。我已经在头中初始化了它。
#ifndef A_H_
#define A_H_
class A {
public:
static const int test = 5;
~A(){};
};
#endif /* A_H_ */
然后我有一个类B,它需要访问类a中的公共静态常量。在本例中,它将把值深度复制到向量中。
#ifndef B_H_
#define B_H_
#include "A.h"
#include <vector>
#include <iostream>
class B {
private:
std::vector<int> testVec;
public:
B(){
testVec.push_back((const int)A::test);
//testVec.push_back(static_cast<const int>(A::test)); //Also works
//testVec.push_back(A::test); //Doesn't work without forward declaration of const int A::test in main or in this header
//(Compiler link error: undefined reference to `A::test')
std::cout<< testVec.front() << std::endl;
}
~B(){};
};
#endif /* B_H_ */
然后主要我简单地调用类B的构造函数。
#include "B.h"
int main() {
B b;
return 0;
}
//Does the cout from ctor of B and prints 5 to the screen.
我的问题是,为什么普通强制转换或静态强制转换允许我访问这个尚未前向声明的静态常量变量。在普通代码中,我会转发声明变量或将其声明为外部变量,因为它已经被定义。为什么强制转换允许我在没有前向声明的情况下访问此变量?(这可能看起来是一个简单的问题,也可能有一个简单答案,但我正在努力加深我的知识)。
编译器链接错误的输出为:
Invoking: Cygwin C++ Linker
g++ -o "S_Test_p1.exe" ./src/S_Test_p1.o
./src/S_Test_p1.o:S_Test_p1.cpp:(.rdata$.refptr._ZN1A4testE[.refptr._ZN1A4testE]+0x0): undefined reference to `A::test'
collect2: error: ld returned 1 exit status
make: *** [makefile:47: S_Test_p1.exe] Error 1
我的主要问题是为什么铸造有效,而不是解决方案是在main或B.h中定义A::test(我知道有效)。我理解这是可以接受和恰当的。主要的问题是关于不可接受的方式,即铸造。在幕后,为什么选角适用于链接
static const int test = 5;
类中static
成员的声明是声明,但不是定义,即使它有初始值设定项。声明通常应该有相应的定义。这个定义看起来像const int A::test;
(不是"正向声明")
然而,还有一条额外的规则,即如果只使用其值,不获取其地址,并且没有引用绑定到它(这类似于获取其地址),则不需要定义整数类型的static const
类成员。
您正在调用的函数是void std::vector<int>::push_back(const int&);
。因此,直接传递A::test
将函数参数引用直接绑定到对象,并且需要定义。
另一方面,如果传递(const int)A::test
或static_cast<const int>(A::test)
,则会强制使用A::test
的值创建临时int
值,而引用则绑定到该临时值。因此,在这种情况下,A::test
的定义是不必要的。
请注意,在C++17中,A::test
的定义在任何情况下都是不必要的,因为在类定义中具有初始值设定项的static
类成员隐含地是inline
变量和定义。
在此之前,请确保在某个*.cpp文件中定义所有类static
成员,以防以需要定义的方式使用它们。
您的代码相当于这个简化的1片段:
struct A { static const int value = 5; };
struct B { const int& n ; B() : n(A::value) {} };
int main()
{
B b;
}
由于未定义(仅声明)A::value
,因此其格式不正确。我的编译器报告链接器错误:
main.cpp:(.text._ZN1BC2Ev[_ZN1BC5Ev]+0xf):对"A::value"的未定义引用
解决方案是正确定义它:
struct A { static const int value = 5; };
struct B { const int& n ; B() : n(A::value) {} };
const int A::value;
int main()
{
B b;
}
1)示例的重要部分是使用对A::test
的引用(请参阅std::vector::push_back()
的定义。这就是为什么我将B
定义为使用对A::value
的引用。
不需要强制转换,它与问题无关。
位于main
顶部的#include "B.h"
表示包括文件"B.h"
的内容。完成后,"B.h"
中的#include "A.h"
表示包含文件"A.h"
的内容。"A.h"
具有A
的定义,这就是编译器了解A::test
的方式。不需要正向声明(事实上,你不能有一个类成员的正向声明),因为编译器已经看到了类的完整定义。
链接问题是因为您还必须在某处定义静态成员。通常,您会有一个.cpp文件,其中包含类的成员函数的定义。该文件还应该定义静态成员:
const int A::test;
- 私有类型的静态常量成员
- 分离一个静态常量 std::thread?
- 从另一个静态常量数组初始化静态常量数组(只需少量计算)
- 我可以在运行时重新定义在 OpenCascade/OCCT 标头中定义的 c++ 静态常量吗?
- 如何为静态常量模板化专用整数值分配存储
- 使用什么代替"静态常量 TCHAR *"
- C++ 模板中的静态常量初始化顺序
- 如何在编译时解析静态常量 std::string?
- 关于静态常量数据模因的声明和定义的混淆
- 将 static_cast<int>(-15) 分配给静态常量字符类型变量
- 为什么在第二类中使用静态常量会在第一类中给出编译器错误?
- 静态常量与常量局部变量,哪一个性能更好
- 如何在模板类中设置静态常量变量
- public:静态常量字符串声明/初始化问题
- 有没有办法声明一个公共静态常量,该常量将使用 constexpr 在源文件中定义(有什么区别)?
- 对静态常量积分类型的未定义引用
- 全局变量中的静态常量与常量
- c++ 类中的静态常量变量和常量变量在存储方面是否有区别
- 避免在静态常量类上定义但不使用
- 指向静态常量对象的共享指针?