我有很多C#代码必须用C++编写。我在C++方面没有太多经验。
我正在使用Visual Studio 2012进行构建。该项目是 C++ 中的静态库(而不是 C++/CLI 中的静态库)。
我正在创建一些 UnitTests,在 C# 版本中,它们有一个类 TestData、许多 TestData 的静态输入和一个静态 Initialize 方法,该方法为这些静态实例设置值。
当我在 C++ 中尝试相同的操作时,我发现如果我的 Initialize 方法在 TestData 类中声明,它不起作用。 但是如果我在外面声明它,它就会起作用。
C++(测试)
TEST_CLASS(UnitTest1)
{
public:
TEST_CLASS_INITIALIZE(ClassInitialize)
{
TestData::Initialize();
}
TEST_METHOD(TestMethod1)
{
Assert::AreEqual(data0.testValue, 30);
}
};
C++(在 TestData 类中初始化方法):
测试失败,并像这样声明初始化方法。当我调试时,我看到正在设置测试值,但是当它到达资产时,它又回到了 0。
//.h
namespace Data
{
class TestData
{
public:
TestData(void);
~TestData(void);
int testValue;
static void Initialize();
};
static TestData data0 = TestData();
}
//.cpp
namespace Data
{
TestData::TestData(void){}
TestData::~TestData(void){}
void TestData::Initialize()
{
data0.testValue = 30;
}
}
C++(在类外部声明的初始化方法):
有了这样的代码,我的测试就可以工作了。
//.h
namespace Data
{
class TestData
{
public:
TestData(void);
~TestData(void);
int testValue;
};
static TestData data0 = TestData();
static void Initialize()
{
data0.testValue = 30;
}
}
为什么会这样?
更新:
按照汉斯的建议,我跟踪了正在使用的变量的地址。它帮助我注意到,由于某种原因,TestData 的构造函数被调用了两次。我不知道为什么。我认为可能正在调用自动分配,所以我在构造函数中添加了一个 int 参数,看看会发生什么,似乎它调用了 data0 的构造函数两次。
当我的测试不起作用(在类中初始化)时,调用顺序为:
- 测试数据 (data0) 构造函数 (地址: 1)
- 测试数据 (data0) 构造函数 (地址: 2)
- 初始化:使用地址为 1 的 data0
- 测试:将 data0 与地址 2 一起使用
当我的测试工作(在类外初始化)时,调用顺序为:
- 测试数据 (data0) 构造函数 (地址: 1)
- 测试数据 (data0) 构造函数 (地址: 2)
- 初始化:使用 data0 和地址 2
- 测试:将 data0 与地址 2 一起使用
现在我明白为什么我的测试失败了。但是我不明白为什么构造函数被调用两次,以及为什么在一种情况下同时使用两个实例,而在另一种情况下只使用第二个实例。
我认为问题与初始化函数是在类内部还是外部定义的无关。这是因为全局变量 data0 和函数定义不在同一文件中。
c++ 中的静态构造与全局变量有另一个含义,这意味着该变量仅在当前文件中可见。
您可以在头文件中定义"静态测试数据数据0 = 测试数据()",并将其包含在 cpp 实现文件中。我想您还将其包含在测试 cpp 文件中,这会导致头文件包含两次。所以实际上有两个 data0 实例。
调试代码时,您会看到实现文件中的"data0"设置为 30,但实际上测试文件中的"data0"并未被触及。
尝试下面的代码,它应该可以正常工作。
.h
class TestData
{
public:
TestData(void);
~TestData(void);
int testValue;
static void Initialize();
};
extern TestData data0;
//.cpp
TestData data0 = TestData();
TestData::TestData(void){}
TestData::~TestData(void){}
void TestData::Initialize()
{
data0.testValue = 30;
}
上面的代码只在头文件中声明 TestData data0(extern 表示变量在其他地方定义),并在 cpp 文件中定义它。因此,在这种情况下,只有一个 data0 实例。