如果我有类似的课程outside.h
:
class Outside
{
public:
Outside(int count);
GetCount();
}
如何使用extern
关键字在 framework.cpp 中使用它,我需要在其中实例化类并调用GetCount
?
编辑:
#include
不被允许。
这里的每个人都有些太温和了。绝对没有理由不想包含 .h 文件。
去吧,包括文件!
只是为了澄清。类是不可能extern
的:
class Outside
{
public:
Outside(int count);
GetCount();
}
但是,一旦您在 framework.cpp 中获得了可用的类,您就可以创建 extern
一个类型为 的对象Outside
。您需要一个 .cpp 文件来声明该变量:
#include "outside.h"
Outside outside(5);
然后您可以通过以下方式在另一个文件中引用该对象extern
(只要您在编译项目时链接到正确的对象文件):
#include "outside.h"
extern Outside outside;
int current_count = outside.GetCount();
extern
用来表示“我知道这个程序运行时会存在一个同名的这种类型的变量,我想使用它。” 它适用于变量/对象,而不是类、结构、联合、类型定义等。它与static
对象没有太大区别。
您可能正在考虑前向声明类以减少编译时间,但是对此有限制(您只能将对象用作不透明的指针,并且不能在它们上调用方法)。
您可能还意味着对Outside
用户隐藏实施。为此,您需要阅读 PIMPL 模式。
一种可能性是向 Outside.h 添加一个免费函数(我还添加了一个命名空间):
namespace X {
class Outside {
int count_;
public:
Outside(int count) : count_(count) { }
int GetCount()
{
return count_;
}
};
int GetOutsideCount(Outside* o);
}
在 .cpp 文件中实现该功能。当您使用它时,您不妨创建您想要的全局变量extern
(注意,变量本身不需要是指针):
#include "outside.h"
namespace X {
int GetOutsideCount(Outside* o)
{
return o->GetCount();
}
}
X::Outside outside(5);
然后在您的程序中执行此操作(请注意,您不能调用任何方法,outside
因为您没有包含 outside.h 并且您不想通过添加类或这些方法的新定义来违反一个定义规则;但是因为定义不可用,您需要将指针传递给outside
周围而不是outside
自身):
namespace X {
class Outside;
int GetOutsideCount(Outside* o);
}
extern X::Outside outside;
int main()
{
int current_count = GetOutsideCount(&outside);
}
委婉地说,我认为这是可憎的。您的程序将找到该GetOutsideCount
函数,并通过传递给它一个Outside*
. Outside::GetCount
实际上被编译成一个普通函数,它接受一个秘密Outside
对象(在Outside::GetCount
该对象内部通过this
指针引用),因此GetOutsideCount
会找到该函数,并告诉它取消引用Outside*
传递给GetOutsideCount
. 我认为这就是所谓的“走很长的路”。
但是它就是这样啊。
如果您不习惯使用extern
关键字,则可以通过以相同方式添加以下两个函数(即,通过前向声明并在旁边实现int GetOUtsideCount()
:
Outside* CreateOutsidePointer(int count)
{
return new Outside(count);
}
void DestroyOutsidePointer(Outside* o)
{
return delete o;
}
我更愿意吞下它。这很像APR使用的策略。
你不会在外部上课。只需包含“outside.h”并创建一个Outside
.
包含文件用于定义,包括类定义。 extern
用于变量。
如果您在源文件中没有类的定义,那么您唯一能做的就是声明它class Outside;
并通过指针传递实例。您实际上无法对实例执行任何操作,包括构造、销毁或调用成员函数(如GetCount()
. 为此,您根本不需要extern
;仅当您想引用另一个源文件中的变量时,才不会让您对它做任何额外的事情。
没有正当理由不在#include
这里使用。唯一的选择是将头文件复制并粘贴到源文件中,这要糟糕得多。任何告诉你不要使用#include
的人都不了解 C++,显然任何认为extern
与这里有任何相关性的人肯定不了解。
如果可能的话,你应该找一位经验丰富的 C++ 开发人员来帮助你学习,建立良好的编码风格,并指导你如何开发 C++。我怀疑你正在做其他事情,以后会变成坏主意。
你不能 extern 类,但你可以 extern 一个创建实例的函数。在消费者代码中:
class Outside;
extern Outside* MakeAnOutside(int count);
extern int GetOutsideCount(Outside* outside);
然后在outside.h中:
Outside* MakeAnOutside(int count)
{
return new Outside(count);
}
int GetOutsideCount(Outside* outside)
{
return outside->GetCount();
}
但是..这可能不是一个好主意..
#include
如果您有一个不允许的愚蠢要求,那么您必须将类声明复制并粘贴到您的.cpp
文件中。需要我说这是一个非常糟糕的主意吗?
这个要求的原因是什么?我很难建议你如何做到这一点。如果您试图避免#include
源文件中的长路径,这是构建问题而不是源代码问题。
您应该使用该选项将目录添加到包含路径gcc -I
,或者为您的编译器添加任何等效项。
如果你真的非常确定这一点,你会想要这样的东西:
// FIXME: Should #include "outside.h" but not allowed.
class Outside
{
public:
Outside(int count);
GetCount();
// Omitted
// void SomeUnusedMethod();
};
<code for framework.cpp here>
void UseOutside()
{
Outside o(5);
std::cout << o.GetCount() << std::endl;
}
然后,我强烈建议您保留声明原样,以便直接从头文件中复制和粘贴。但是如果你想修剪它,你可以省略任何你不使用的非虚拟方法。您需要保留所有变量。
将您的 Outside 类的包含放在 StdAfx.h 或 framework.cpp已经包含的任何其他头文件中。
我只能想到一个用例,您可以在没有#include 标题或复制其他人建议的类定义的情况下“extern”一个类。
如果您需要保留指向该类的指针,但您从不直接取消引用它,只传递它,那么您可以在文件中执行以下操作:
class Outside;
class MyClass
{
Outside* pOutside;
void SetOutsidePointer(Outside *p) {pOutside = p;}
Outside* GetOutsidePointer() { return pOutside;}
/* the rest of the stuff */
}
这只有在您从不打电话pOutside->GetCount()
或new Outside
在您的文件中才有效。
我认为您误解了存储类,其中之一是外部的。
"声明为extern的对象和变量将在另一个翻译单元或封闭范围中定义的对象声明为具有外部链接。"
所以标记 extern 是针对变量而不是类定义/声明
因此,如果您不能包含 .h,我建议您将 .h 和 .cpp 构建为静态库或 dll 并在您的代码中使用
哎呀...我们将类放在头文件中并使用#include 将类(或其他)声明复制到多个cpp文件(称为编译单元)中。
如果你真的不能使用#include,你会留下一个手动副本,如上所述,当有人更改原始文件时,它有一个明显的过时问题。这将完全破坏您的测试代码,难以跟踪崩溃。
如果你坚持要沿着这个手册副本的路走下去,你确实需要整个类声明。从技术上讲,您可以省略某些零碎的部分,但这是一个坏主意——显然您的团队对 C++ 结构没有深入的了解,因此您可能会犯错误。其次,C++ 对象模型没有跨编译器标准化。从理论上讲,即使是简单的非虚拟方法也可能会改变模型,从而破坏您的测试。
“长路径”确实不是不直接包含文件的好理由。但是,如果您真的不能,请将整个头文件复制到 #include 本来应该存在的位置——这正是 C 预处理器要做的事情。