静态强制转换以访问静态常量类成员

Static Cast to access static const class member

本文关键字:静态 常量 成员 访问 转换      更新时间:2023-10-16

所以昨天我在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::teststatic_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;