我最近在C ++程序中遇到过一些我无法完全理解的行为。让我通过简单的例子来解释这种行为。
1。 第一个静态库
在层次结构的最底层,我有一个静态库 - 让它命名为 FirstLIB 。该库包括两对头/源文件。 sample.h 头文件包含 MyClass 类定义。相应的 sample.cpp 文件包含此类(其方法)的实现。代码如下:
sample.h
#ifndef __sample_h
#define __sample_h
namespace SampleNamespace
{
class MyClass
{
int counter;
public:
MyClass();
int GetCounter();
void SetCounter(int value);
};
}
#endif
和 sample.cpp
#include <iostream>
#include "sample.h"
namespace SampleNamespace
{
MyClass::MyClass(): counter(0)
{
std::cout << "Inside of MyClass constructor!" << std::endl;
}
int MyClass::GetCounter() { return counter; }
void MyClass::SetCounter(int value) { counter = value; }
}
之后, dvcl.h 文件声明用于操作MyClass对象的简单API, dvcl.cpp 实现此API。请注意,dvcl.cpp文件包含此API的方法使用的MyClass对象的定义,这一点很重要。变量定义为static,因此它只在此源文件中可见。
dvcl.h
#ifndef _dvcl_h
#define _dvcl_h
void DVCL_Initialize(int counter);
int DVCL_GetCounter();
void DVCL_SetCounter(int value);
#endif
dvcl.cpp
#include "dvcl.h"
#include "sample.h"
static SampleNamespace::MyClass myClass;
void DVCL_Initialize(int counter)
{
myClass.SetCounter(counter);
}
int DVCL_GetCounter()
{
return myClass.GetCounter();
}
void DVCL_SetCounter(int value)
{
myClass.SetCounter(value);
}
2。第二个静态库
第二个静态库 - 让它命名为 SecondLIB - 比第一个更简单。它只包含一个标头/源对。 dvconference_client.h 标头声明了一个函数,而 dvconference_client.cpp 实现了此函数。 dvconference_client.cpp还包括dvcl.h头文件(它将触发dvcl.cpp源代码的编译)。代码可以在下面找到:
dvconference_client.h
#ifndef __external_file
#define __external_file
int DoSomething();
#endif
dvconference.cpp
#include "dvconference_client.h"
#include "dvcl.h"
int DoSomething()
{
return DVCL_GetCounter();
}
第3。主要可执行文件
最后,主要可执行文件 MainEXE 仅包含一个main.cpp文件。该源包括dvconference_client.h和dvcl.h头文件。代码如下:
#include <iostream>
#include "dvconference_client.h"
#include "dvcl.h"
int main()
{
std::cout << DoSomething() << std::endl;
std::cout << DVCL_GetCounter() << std::endl;
return 0;
}
4。我的疑惑和疑问:
我希望更有经验的同事可以清除我的疑虑(我为很长的帖子道歉)。
答案 0 :(得分:2)
对于referenec,编译阶段 源代码 - &gt;预处理 - &gt;编译 - &gt;链接 - &gt; loading - &gt;执行
是的,“。c / .cpp”文件只编译一次。但是每个包含都会解析标题。
是对象只执行一次,因为相应的对象文件只链接并加载一次。
答案 1 :(得分:1)
第一点:
dvcl
编译单元位于静态库中。如果未使用代码,则编译对象(.o)不包含在生成的可执行文件中。因此,static SampleNamespace::MyClass myClass;
永远不会被执行。如果您在链接时使用动态库或明确链接.o文件,则不一样。
第二点:
使用或不使用库,源文件(.c)或(.cpp)仅编译(并链接到可执行文件)一次。这就是在其他文件中包含包含的.h文件的原因,因此每个包含文件一次处理
第三点:
该对象有效地实例化一次,因为.o文件只链接一次