Static Cast访问静态const类成员

时间:2017-10-18 12:24:45

标签: c++ casting

所以昨天我一直在寻找SO而无法找到以下答案。这种情况来自我正在使用的一些代码,但这是MCVE来演示它。

我在A.h中定义了一个A类,其中只有一个静态const。我已经在标题中初始化了它。

#ifndef A_H_
#define A_H_
class A {
public:
    static const int test = 5;
    ~A(){};
};


#endif /* A_H_ */

然后我有一个B类需要从类A访问公共静态const。在这个例子中,它会将值深度复制到向量。

#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_ */

然后在main中我简单地调用了B类的构造函数。

#include "B.h"

int main() {

    B b;

    return 0;
}
//Does the cout from ctor of B and prints 5 to the screen. 

我的问题是为什么普通的强制转换或静态强制转换允许我访问这个尚未向前声明的静态const变量。在普通代码中,我会转发声明变量或将其声明为extern,因为它已经被定义。为什么铸造允许我在没有前向声明的情况下访问此变量的原因是什么? (这可能看起来像一个简单的问题,可能有一个简单的答案,但我想在这里进一步了解我的知识)。

编译器链接错误的输出是:

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。我明白这是可以接受的。主要问题是关于不可接受的方式,即铸造。在幕后为什么投射工作用于链接?

3 个答案:

答案 0 :(得分:7)

static之类的static const int test = 5;成员的声明是声明,但不是定义,即使它有初始值设定项。声明通常应该有相应的定义。这个定义看起来像const int A::test;(这不是&#34;前向声明&#34;。)

然而,还有一个额外的规则是,如果只使用其值,不使用其地址,并且没有引用绑定到它,则不需要定义整数类型的static const类成员(这与取其地址相似)。

您调用的功能是void std::vector<int>::push_back(const int&);。因此,直接传递A::test会将函数参数引用直接绑定到对象,并需要定义。

另一方面,如果您传递(const int)A::teststatic_cast<const int>(A::test),则会强制使用int的值创建临时A::test值,并且参考绑定而是临时的。因此,在这种情况下,A::test的定义不是必需的。

注意在C ++ 17中,A::test的定义在任何情况下都不是必需的,因为在类定义中具有初始值设定项的static类成员是隐含的inline类成员。 1}}变量和定义。

在此之前,请务必在某些* .cpp文件中定义所有类static成员,以防您以需要定义的方式使用它们。

答案 1 :(得分:1)

您的代码等同于此简化的 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的引用的使用(请参阅definition of std::vector::push_back()。这就是我定义使用B的原因对A::value的引用。

答案 2 :(得分:0)

不需要演员,这与问题无关。

#include "B.h"顶部的main表示要包含文件"B.h"的内容。完成后,#include "A.h"中的"B.h"表示要包含文件"A.h"的内容。 "A.h"具有A的定义,以及编译器对A::test的了解。不需要前向声明(事实上,你不能拥有类成员的前向声明),因为编译器已经看到了类的完整定义。

链接问题是因为您还必须在某处定义静态成员。通常,您将拥有一个.cpp文件,该文件具有该类成员函数的定义。该文件还应定义静态成员:

const int A::test;