如何使用extern而不是#include在源文件中使用头文件中的类?

时间:2021-08-26 19:40:09

If I have a class in outside.h like:

如果我在outside.h中有一个类,如:

class Outside
{
   public:
       Outside(int count);
       GetCount();
}

How can I use it in framework.cpp using the extern keyword, where I need to instantiate the class and call GetCount?

如何使用extern关键字在framework.cpp中使用它,我需要实例化类并调用GetCount?


Edit:

#include is not allowed.

#include是不允许的。

10 个解决方案

#1


Just to clarify. It is impossible to extern the class:

只是为了澄清。这个班是不可能的:

class Outside
{
    public:
        Outside(int count);
        GetCount();
}

But, once you have the class available in framework.cpp, you CAN extern an object of type Outside. You'll need a .cpp file declaring that variable:

但是,一旦你在framework.cpp中有了这个类,你就可以extern一个类型为Outside的对象。你需要一个声明该变量的.cpp文件:

#include "outside.h"

Outside outside(5);

And then you can refer to that object in another file via extern (as long as you link in the correct object file when you compile your project):

然后你可以通过extern在另一个文件中引用该对象(只要在编译项目时链接到正确的目标文件中):

#include "outside.h"

extern Outside outside;
int current_count = outside.GetCount();

extern is used to say "I KNOW a variable of this type with this name will exist when this program runs, and I want to use it." It works with variables/objects, not classes, structs, unions, typedefs, etc. It's not much different from static objects.

extern用来说“我知道这个类型的变量,当这个程序运行时,这个名字就会存在,我想用它。”它适用于变量/对象,而不是类,结构,联合,typedef等。它与静态对象没有太大区别。

You may be thinking about forward declaring classes to cut down on compile times, but there are restrictions on that (you only get to use the objects as opaque pointers and are not able to call methods on them).

您可能正在考虑向前声明类以减少编译时间,但是存在限制(您只能将对象用作不透明指针并且无法调用它们上的方法)。

You may also mean to hide the implementation of Outside from users. In order to do that, you're going to want to read up on the PIMPL pattern.

您可能还想隐藏用户的Outside实现。为了做到这一点,你将要阅读PIMPL模式。


Update

One possibility would be to add a free function to Outside.h (I've also added a namespace):

一种可能性是向Outside.h添加一个*函数(我还添加了一个名称空间):

namespace X {
    class Outside {
        int count_;
        public:
            Outside(int count) : count_(count) { }
            int GetCount()
            {
                return count_;
            }
    };

    int GetOutsideCount(Outside* o);
}

Implement that function in a .cpp file. While you're at it, you might as well make the global variable that you intend to extern (note, the variable itself does not need to be a pointer):

在.cpp文件中实现该功能。当你在它的时候,你也可以创建你想要extern的全局变量(注意,变量本身不需要是一个指针):

#include "outside.h"

namespace X {
    int GetOutsideCount(Outside* o)
    {
        return o->GetCount();
    }
}

X::Outside outside(5);

And then do this in your program (note that you cannot call any methods on outside because you did not include outside.h and you don't want to violate the one definition rule by adding a new definition of the class or those methods; but since the definitions are unavailable you'll need to pass pointers to outside around and not outside itself):

然后在您的程序中执行此操作(请注意,您不能在外部调用任何方法,因为您没有包含outside.h并且您不希望通过添加类的新定义或那些方法来违反一个定义规则;但是由于定义不可用,您需要将指针传递到外部而不是外部):

namespace X {
    class Outside;
    int GetOutsideCount(Outside* o);
}

extern X::Outside outside;

int main()
{
    int current_count = GetOutsideCount(&outside);
}

I consider this an abomination, to put it mildly. Your program will find the GetOutsideCount function, call it by passing it an Outside*. Outside::GetCount is actually compiled to a normal function that takes a secret Outside object (inside Outside::GetCount that object is referred to via the this pointer), so GetOutsideCount will find that function, and tell it to dereference the Outside* that was passed to GetOutsideCount. I think that's called "going the long way 'round."

我认为这是令人憎恶的,温和地说。您的程序将找到GetOutsideCount函数,通过将其传递给Outside *来调用它。 Outside :: GetCount实际上编译为一个普通函数,它接受一个秘密的Outside对象(在Outside :: GetCount里面,该对象通过this指针引用),所以GetOutsideCount将找到该函数,并告诉它取消引用Outside *被传递给GetOutsideCount。我认为这被称为“走很远的路”。

But it is what it is.

但是它就是这样啊。

If you aren't married to using the extern keyword, you can instead go full "let's use C++ like it's C" mode by adding the following two functions in the same way (i.e., via forward declarations and implementing right next to int GetOUtsideCount():

如果你没有使用extern关键字,你可以通过以相同的方式添加以下两个函数来完全“让我们使用C ++就像它的C”模式(即通过前向声明和实现紧邻int GetOUtsideCount( ):

Outside* CreateOutsidePointer(int count)
{
    return new Outside(count);
}

void DestroyOutsidePointer(Outside* o)
{
    return delete o;
}

I'm more willing to swallow that. It's a lot like the strategy used by the APR.

我更愿意吞下那个。这很像APR使用的策略。

#2


Everyone here is a bit too gentle. There is ABSOLUTELY NO REASON why you would not want to include the .h file.

这里的每个人都有点太温柔。绝对没有理由为什么你不想包含.h文件。

Go for it and include the file!

去吧,包括文件!

#3


You don't make classes extern. Just include "outside.h" and create an instance of Outside.

你不做外部课。只需包含“outside.h”并创建一个Outside实例。

#4


you cant extern the class, but you can extern a function that creates an instance.. In the consumer code:

你不能extern这个类,但你可以extern一个创建实例的函数..在消费者代码中:

class Outside;

extern Outside* MakeAnOutside(int count);
extern int GetOutsideCount(Outside* outside);

Then in outside.h:

然后在outside.h:

Outside* MakeAnOutside(int count)
{
   return new Outside(count);
}

int  GetOutsideCount(Outside* outside)
{
  return outside->GetCount();
}

but.. this may not be a good idea..

但是......这可能不是一个好主意..

#5


Include files are for definitions, including class definitions. extern is for variables.

包含文件用于定义,包括类定义。 extern是变量。

If you don't have the definition of a class in a source file, about the only thing you can do with it is declare it with class Outside; and pass instances around by pointer. You can't actually do anything with the instances, including construction, destruction, or calling member functions like GetCount(). For this, you don't need extern at all; only if you want to refer to a variable in another source file, and that won't let you do anything additional with it.

如果你没有在源文件中定义类,那么你可以用它来做的唯一事情是用class Outside声明它;并通过指针传递实例。您实际上无法对实例执行任何操作,包括构造,销毁或调用成员函数(如GetCount())。为此,你根本不需要extern;只有当你想引用另一个源文件中的变量时,才会让你做任何额外的事情。

There is no valid reason not to use #include here. The only alternative is to copy-and-paste the header file into the source file, and that's considerably worse. Anybody who tells you not to use #include does not understand C++, and obviously anybody who thinks extern has any relevance here certainly doesn't.

没有正当理由不在此处使用#include。唯一的选择是将头文件复制并粘贴到源文件中,这更糟糕。任何告诉你不要使用#include的人都不懂C ++,显然任何认为extern在这里有任何相关性的人肯定不会。

If at all possible, you should get an experienced C++ developer to help you learn, establish good coding styles, and mentor you in how to develop C++. I suspect you're doing other things that will turn out to be Bad Ideas later on.

如果可能的话,你应该找一位经验丰富的C ++开发人员来帮助你学习,建立良好的编码风格,并指导你如何开发C ++。我怀疑你其他的事情后来会变成坏主意。

#6


If you had a silly requirement that #include is not allowed then you'd have to copy and paste the class declaration into your .cpp file. Need I say that'd be a very bad idea?

如果您有一个愚蠢的要求,即不允许#include,那么您必须将类声明复制并粘贴到.cpp文件中。我需要说这是一个非常糟糕的主意吗?

What is the reason for this requirement? It pains me to advise you how to do this. If you are trying to avoid long #include paths in your source files, this is a build problem not a source code problem.

这个要求的原因是什么?我很难告诉你如何做到这一点。如果您试图避免源文件中的长#include路径,这是一个构建问题,而不是源代码问题。

You should add directories to the include path with the gcc -I option, or whatever the equivalent is for your compiler.

您应该使用gcc -I选项将目录添加到包含路径,或者为编译器添加等效项。

If you are really, really sure about this, you'd want something like this:

如果你真的非常确定这一点,你会想要这样的东西:

framework.cpp

// 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;
}

I would then strongly recommend you leave the declaration as is so it's just straight copy-and-pasted from the header file. But if you want to trim it you can omit any non-virtual methods you don't use. You'll need to keep all variables.

然后我强烈建议你保留声明,这样它就可以直接从头文件中复制粘贴。但是如果你想修剪它,你可以省略任何你不使用的非虚方法。你需要保留所有变量。

#7


I can only think of one use case where you could 'extern' a class without either #including the header or duplicating the class definition as others have suggested.

我只能想到一个用例,你可以'extern'一个类,没有#include标题或复制类定义,正如其他人所建议的那样。

If you need to keep pointer to the class but you never dereference it directly, only pass it around, then you can do the following in your file:

如果你需要保持指向类的指针,但你从不直接取消引用它,只传递它,然后你可以在你的文件中执行以下操作:

class Outside;
class MyClass
{  
   Outside* pOutside;
   void SetOutsidePointer(Outside *p) {pOutside = p;}
   Outside* GetOutsidePointer() { return pOutside;}
   /* the rest of the stuff */
}

This will only work if you never call pOutside->GetCount() or new Outside in your file.

这只有在您从未在文件中调用pOutside-> GetCount()或new Outside时才有效。

#8


Put the include for your Outside class in the StdAfx.h or any other headerfile that framework.cpp is already including.

将您的Outside类的include放在StdAfx.h或framework.cpp已经包含的任何其他头文件中。

#9


I think you misunderstand the storage classes and one of them is the external.

我认为你误解了存储类,其中一个是外部的。

"Objects and variables declared as extern declare an object that is defined in another translation unit or in an enclosing scope as having external linkage."

“声明为extern的对象和变量声明一个对象,该对象在另一个翻译单元或封闭范围内定义为具有外部链接。”

So marking extern is for variables not classes defination/declaration

所以标记extern是变量而不是类定义/声明

So if you can not include the .h, I recommend you to build the .h and .cpp to be static lib or dll and use in your code

因此,如果您不能包含.h,我建议您将.h和.cpp构建为静态lib或dll并在代码中使用

#10


Yikes... we put classes in header files and use #include in order to duplicate class (or other) declarations into multiple cpp files (called compilation units).

Yikes ...我们将类放在头文件中并使用#include将类(或其他)声明复制到多个cpp文件(称为编译单元)中。

If you really can't use #include, you're left with a manual copy, as suggested above, which has the obvious problem of becoming outdated when someone changes the original. That'll completely break your test code with hard to track crashes.

如果你真的不能使用#include,你就会留下一个手动副本,如上所述,当有人改变原版时,这个问题显然已经过时了。这将彻底破坏您的测试代码,难以跟踪崩溃。

If you insist on going down the path of this manual copy, you do need the entire class declaration. Technically, you could omit certain bits and pieces, but this is a bad idea -- clearly your team doesn't have deep understanding of C++ constructs, so you're likely to make a mistake. Second, the C++ object model is not standardized across compilers. Theoretically even a simple non-virtual method could change the model, breaking your test.

如果您坚持沿着本手册的路径走下去,那么您需要完整的类声明。从技术上讲,你可以省略某些零碎,但这是一个坏主意 - 显然你的团队对C ++结构没有深刻的理解,所以你可能会犯错。其次,C ++对象模型在编译器之间没有标准化。从理论上讲,即使是简单的非虚拟方法也可能会改变模型,从而破坏您的测试。

A "long path" is really not a great reason not to include a file directly. But if you really can't, copy the entire header file in where #include would have been -- that's exactly what the C preprocessor is going to do anyway.

“长路径”实际上并不是不直接包含文件的重要原因。但是如果你真的不能,那么将整个头文件复制到#include所在的位置 - 这正是C预处理器无论如何要做的事情。

#1


Just to clarify. It is impossible to extern the class:

只是为了澄清。这个班是不可能的:

class Outside
{
    public:
        Outside(int count);
        GetCount();
}

But, once you have the class available in framework.cpp, you CAN extern an object of type Outside. You'll need a .cpp file declaring that variable:

但是,一旦你在framework.cpp中有了这个类,你就可以extern一个类型为Outside的对象。你需要一个声明该变量的.cpp文件:

#include "outside.h"

Outside outside(5);

And then you can refer to that object in another file via extern (as long as you link in the correct object file when you compile your project):

然后你可以通过extern在另一个文件中引用该对象(只要在编译项目时链接到正确的目标文件中):

#include "outside.h"

extern Outside outside;
int current_count = outside.GetCount();

extern is used to say "I KNOW a variable of this type with this name will exist when this program runs, and I want to use it." It works with variables/objects, not classes, structs, unions, typedefs, etc. It's not much different from static objects.

extern用来说“我知道这个类型的变量,当这个程序运行时,这个名字就会存在,我想用它。”它适用于变量/对象,而不是类,结构,联合,typedef等。它与静态对象没有太大区别。

You may be thinking about forward declaring classes to cut down on compile times, but there are restrictions on that (you only get to use the objects as opaque pointers and are not able to call methods on them).

您可能正在考虑向前声明类以减少编译时间,但是存在限制(您只能将对象用作不透明指针并且无法调用它们上的方法)。

You may also mean to hide the implementation of Outside from users. In order to do that, you're going to want to read up on the PIMPL pattern.

您可能还想隐藏用户的Outside实现。为了做到这一点,你将要阅读PIMPL模式。


Update

One possibility would be to add a free function to Outside.h (I've also added a namespace):

一种可能性是向Outside.h添加一个*函数(我还添加了一个名称空间):

namespace X {
    class Outside {
        int count_;
        public:
            Outside(int count) : count_(count) { }
            int GetCount()
            {
                return count_;
            }
    };

    int GetOutsideCount(Outside* o);
}

Implement that function in a .cpp file. While you're at it, you might as well make the global variable that you intend to extern (note, the variable itself does not need to be a pointer):

在.cpp文件中实现该功能。当你在它的时候,你也可以创建你想要extern的全局变量(注意,变量本身不需要是一个指针):

#include "outside.h"

namespace X {
    int GetOutsideCount(Outside* o)
    {
        return o->GetCount();
    }
}

X::Outside outside(5);

And then do this in your program (note that you cannot call any methods on outside because you did not include outside.h and you don't want to violate the one definition rule by adding a new definition of the class or those methods; but since the definitions are unavailable you'll need to pass pointers to outside around and not outside itself):

然后在您的程序中执行此操作(请注意,您不能在外部调用任何方法,因为您没有包含outside.h并且您不希望通过添加类的新定义或那些方法来违反一个定义规则;但是由于定义不可用,您需要将指针传递到外部而不是外部):

namespace X {
    class Outside;
    int GetOutsideCount(Outside* o);
}

extern X::Outside outside;

int main()
{
    int current_count = GetOutsideCount(&outside);
}

I consider this an abomination, to put it mildly. Your program will find the GetOutsideCount function, call it by passing it an Outside*. Outside::GetCount is actually compiled to a normal function that takes a secret Outside object (inside Outside::GetCount that object is referred to via the this pointer), so GetOutsideCount will find that function, and tell it to dereference the Outside* that was passed to GetOutsideCount. I think that's called "going the long way 'round."

我认为这是令人憎恶的,温和地说。您的程序将找到GetOutsideCount函数,通过将其传递给Outside *来调用它。 Outside :: GetCount实际上编译为一个普通函数,它接受一个秘密的Outside对象(在Outside :: GetCount里面,该对象通过this指针引用),所以GetOutsideCount将找到该函数,并告诉它取消引用Outside *被传递给GetOutsideCount。我认为这被称为“走很远的路”。

But it is what it is.

但是它就是这样啊。

If you aren't married to using the extern keyword, you can instead go full "let's use C++ like it's C" mode by adding the following two functions in the same way (i.e., via forward declarations and implementing right next to int GetOUtsideCount():

如果你没有使用extern关键字,你可以通过以相同的方式添加以下两个函数来完全“让我们使用C ++就像它的C”模式(即通过前向声明和实现紧邻int GetOUtsideCount( ):

Outside* CreateOutsidePointer(int count)
{
    return new Outside(count);
}

void DestroyOutsidePointer(Outside* o)
{
    return delete o;
}

I'm more willing to swallow that. It's a lot like the strategy used by the APR.

我更愿意吞下那个。这很像APR使用的策略。

#2


Everyone here is a bit too gentle. There is ABSOLUTELY NO REASON why you would not want to include the .h file.

这里的每个人都有点太温柔。绝对没有理由为什么你不想包含.h文件。

Go for it and include the file!

去吧,包括文件!

#3


You don't make classes extern. Just include "outside.h" and create an instance of Outside.

你不做外部课。只需包含“outside.h”并创建一个Outside实例。

#4


you cant extern the class, but you can extern a function that creates an instance.. In the consumer code:

你不能extern这个类,但你可以extern一个创建实例的函数..在消费者代码中:

class Outside;

extern Outside* MakeAnOutside(int count);
extern int GetOutsideCount(Outside* outside);

Then in outside.h:

然后在outside.h:

Outside* MakeAnOutside(int count)
{
   return new Outside(count);
}

int  GetOutsideCount(Outside* outside)
{
  return outside->GetCount();
}

but.. this may not be a good idea..

但是......这可能不是一个好主意..

#5


Include files are for definitions, including class definitions. extern is for variables.

包含文件用于定义,包括类定义。 extern是变量。

If you don't have the definition of a class in a source file, about the only thing you can do with it is declare it with class Outside; and pass instances around by pointer. You can't actually do anything with the instances, including construction, destruction, or calling member functions like GetCount(). For this, you don't need extern at all; only if you want to refer to a variable in another source file, and that won't let you do anything additional with it.

如果你没有在源文件中定义类,那么你可以用它来做的唯一事情是用class Outside声明它;并通过指针传递实例。您实际上无法对实例执行任何操作,包括构造,销毁或调用成员函数(如GetCount())。为此,你根本不需要extern;只有当你想引用另一个源文件中的变量时,才会让你做任何额外的事情。

There is no valid reason not to use #include here. The only alternative is to copy-and-paste the header file into the source file, and that's considerably worse. Anybody who tells you not to use #include does not understand C++, and obviously anybody who thinks extern has any relevance here certainly doesn't.

没有正当理由不在此处使用#include。唯一的选择是将头文件复制并粘贴到源文件中,这更糟糕。任何告诉你不要使用#include的人都不懂C ++,显然任何认为extern在这里有任何相关性的人肯定不会。

If at all possible, you should get an experienced C++ developer to help you learn, establish good coding styles, and mentor you in how to develop C++. I suspect you're doing other things that will turn out to be Bad Ideas later on.

如果可能的话,你应该找一位经验丰富的C ++开发人员来帮助你学习,建立良好的编码风格,并指导你如何开发C ++。我怀疑你其他的事情后来会变成坏主意。

#6


If you had a silly requirement that #include is not allowed then you'd have to copy and paste the class declaration into your .cpp file. Need I say that'd be a very bad idea?

如果您有一个愚蠢的要求,即不允许#include,那么您必须将类声明复制并粘贴到.cpp文件中。我需要说这是一个非常糟糕的主意吗?

What is the reason for this requirement? It pains me to advise you how to do this. If you are trying to avoid long #include paths in your source files, this is a build problem not a source code problem.

这个要求的原因是什么?我很难告诉你如何做到这一点。如果您试图避免源文件中的长#include路径,这是一个构建问题,而不是源代码问题。

You should add directories to the include path with the gcc -I option, or whatever the equivalent is for your compiler.

您应该使用gcc -I选项将目录添加到包含路径,或者为编译器添加等效项。

If you are really, really sure about this, you'd want something like this:

如果你真的非常确定这一点,你会想要这样的东西:

framework.cpp

// 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;
}

I would then strongly recommend you leave the declaration as is so it's just straight copy-and-pasted from the header file. But if you want to trim it you can omit any non-virtual methods you don't use. You'll need to keep all variables.

然后我强烈建议你保留声明,这样它就可以直接从头文件中复制粘贴。但是如果你想修剪它,你可以省略任何你不使用的非虚方法。你需要保留所有变量。

#7


I can only think of one use case where you could 'extern' a class without either #including the header or duplicating the class definition as others have suggested.

我只能想到一个用例,你可以'extern'一个类,没有#include标题或复制类定义,正如其他人所建议的那样。

If you need to keep pointer to the class but you never dereference it directly, only pass it around, then you can do the following in your file:

如果你需要保持指向类的指针,但你从不直接取消引用它,只传递它,然后你可以在你的文件中执行以下操作:

class Outside;
class MyClass
{  
   Outside* pOutside;
   void SetOutsidePointer(Outside *p) {pOutside = p;}
   Outside* GetOutsidePointer() { return pOutside;}
   /* the rest of the stuff */
}

This will only work if you never call pOutside->GetCount() or new Outside in your file.

这只有在您从未在文件中调用pOutside-> GetCount()或new Outside时才有效。

#8


Put the include for your Outside class in the StdAfx.h or any other headerfile that framework.cpp is already including.

将您的Outside类的include放在StdAfx.h或framework.cpp已经包含的任何其他头文件中。

#9


I think you misunderstand the storage classes and one of them is the external.

我认为你误解了存储类,其中一个是外部的。

"Objects and variables declared as extern declare an object that is defined in another translation unit or in an enclosing scope as having external linkage."

“声明为extern的对象和变量声明一个对象,该对象在另一个翻译单元或封闭范围内定义为具有外部链接。”

So marking extern is for variables not classes defination/declaration

所以标记extern是变量而不是类定义/声明

So if you can not include the .h, I recommend you to build the .h and .cpp to be static lib or dll and use in your code

因此,如果您不能包含.h,我建议您将.h和.cpp构建为静态lib或dll并在代码中使用

#10


Yikes... we put classes in header files and use #include in order to duplicate class (or other) declarations into multiple cpp files (called compilation units).

Yikes ...我们将类放在头文件中并使用#include将类(或其他)声明复制到多个cpp文件(称为编译单元)中。

If you really can't use #include, you're left with a manual copy, as suggested above, which has the obvious problem of becoming outdated when someone changes the original. That'll completely break your test code with hard to track crashes.

如果你真的不能使用#include,你就会留下一个手动副本,如上所述,当有人改变原版时,这个问题显然已经过时了。这将彻底破坏您的测试代码,难以跟踪崩溃。

If you insist on going down the path of this manual copy, you do need the entire class declaration. Technically, you could omit certain bits and pieces, but this is a bad idea -- clearly your team doesn't have deep understanding of C++ constructs, so you're likely to make a mistake. Second, the C++ object model is not standardized across compilers. Theoretically even a simple non-virtual method could change the model, breaking your test.

如果您坚持沿着本手册的路径走下去,那么您需要完整的类声明。从技术上讲,你可以省略某些零碎,但这是一个坏主意 - 显然你的团队对C ++结构没有深刻的理解,所以你可能会犯错。其次,C ++对象模型在编译器之间没有标准化。从理论上讲,即使是简单的非虚拟方法也可能会改变模型,从而破坏您的测试。

A "long path" is really not a great reason not to include a file directly. But if you really can't, copy the entire header file in where #include would have been -- that's exactly what the C preprocessor is going to do anyway.

“长路径”实际上并不是不直接包含文件的重要原因。但是如果你真的不能,那么将整个头文件复制到#include所在的位置 - 这正是C预处理器无论如何要做的事情。