如果我在outside.h
中有一个班级,那么:
class Outside
{
public:
Outside(int count);
GetCount();
}
如何使用extern
关键字在framework.cpp中使用它,我需要实例化该类并调用GetCount
?
#include
是不允许的。
答案 0 :(得分:6)
这里的每个人都有点太温柔了。 绝对没有理由为什么你不想要包含.h文件。
去寻找并包含文件!
答案 1 :(得分:5)
只是澄清一下。 extern
课程是不可能的:
class Outside
{
public:
Outside(int count);
GetCount();
}
但是,一旦你在framework.cpp中有了这个类,你就 CAN extern
一个Outside
类型的对象。你需要一个声明该变量的.cpp文件:
#include "outside.h"
Outside outside(5);
然后你可以通过extern
在另一个文件中引用该对象(只要在编译项目时链接到正确的目标文件中):
#include "outside.h"
extern Outside outside;
int current_count = outside.GetCount();
extern
用于表示“我知道此类型的变量,此程序运行时将存在此名称,我想使用它。”它适用于变量/对象,而不是类,结构,联合,typedef等。它与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*
的{{1}}。我认为这被称为“走很长的路”。
但事实就是如此。
如果你没有使用GetOutsideCount
关键字,那么你可以通过以相同的方式添加以下两个函数来完全“让我们使用C ++就像它的C”模式(即通过前向声明和在extern
旁边执行:
int GetOUtsideCount()
我更愿意吞下那个。这很像APR使用的策略。
答案 2 :(得分:4)
你不要把课程设为外部。只需包含“outside.h”并创建Outside
的实例。
答案 3 :(得分:3)
你不能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();
}
但是......这可能不是一个好主意..
答案 4 :(得分:3)
包含文件用于定义,包括类定义。 extern
用于变量。
如果您没有在源文件中定义类,那么您可以使用class Outside;
声明它,并通过指针传递实例。实际上,您无法对实例执行任何操作,包括构造,销毁或调用GetCount()
之类的成员函数。为此,您根本不需要extern
;只有当你想引用另一个源文件中的变量时,才会让你做任何额外的事情。
没有正当理由不在此处使用#include
。唯一的选择是将头文件复制并粘贴到源文件中,这更糟糕。任何告诉你不要使用#include
的人都不懂C ++,显然任何认为extern
与此有任何关联的人肯定不会。
如果可能的话,你应该找一位经验丰富的C ++开发人员来帮助你学习,建立良好的编码风格,并指导你如何开发C ++。我怀疑你其他的事情后来会变成坏主意。
答案 5 :(得分:2)
如果您有一个愚蠢的要求,#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;
}
然后我强烈建议您保留声明,这样它就可以直接从头文件中复制粘贴。但是如果你想修剪它,你可以省略任何你不使用的非虚方法。你需要保留所有变量。
答案 6 :(得分:2)
我只能想到一个用例,你可以'extern'一个类,没有#include标题或复制类定义,正如其他人所建议的那样。
如果您需要保持指向该类的指针,但您从不直接取消引用它,只能传递它,然后您可以在您的文件中执行以下操作:
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
的情况。
答案 7 :(得分:2)
将您的Outside类的include放在StdAfx.h或framework.cpp 已经的任何其他头文件中。
答案 8 :(得分:1)
我认为你误解了存储类,其中一个是外部的。
“对象和变量声明为 extern ,声明在另一个翻译单元或封闭范围内定义为具有外部链接的对象。”
因此标记extern是变量而不是类定义/声明
因此,如果您不能包含.h,我建议您将.h和.cpp构建为静态lib或dll并在代码中使用
答案 9 :(得分:1)
Yikes ...我们将类放在头文件中并使用#include将类(或其他)声明复制到多个cpp文件中(称为编译单元)。
如果你真的不能使用#include,你会留下一个手动副本,如上所述,当有人改变原版时,这个问题显然已经过时了。这将彻底破坏您的测试代码,难以跟踪崩溃。
如果您坚持沿着本手册的路径走下去,您需要整个班级声明。从技术上讲,你可以省略某些零碎,但这是一个坏主意 - 显然你的团队对C ++结构没有深刻的理解,所以你可能会犯错。其次,C ++对象模型在编译器之间没有标准化。从理论上讲,即使是简单的非虚拟方法也可能会改变模型,从而破坏您的测试。
“长路径”实际上并不是不直接包含文件的重要原因。但是如果你真的不能,那么将整个头文件复制到#include所在的位置 - 这正是C预处理器无论如何都会做的。