tags:

views:

387

answers:

10

If I have a class in outside.h like:

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?


Edit:

#include is not allowed.

+4  A: 

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

eduffy
Yes but for this case, include is not allowed. Project requirements.
Joan Venge
It isn't possible to use a class without its declaration being included in the file. Otherwise, the compiler has no idea what the structure of the class is, or how to use it. Can you give us some details of the project?
Joe M
Yeah writing the declaration is fine. How do I do that? I just don't know what to "include" into the framework.cpp.
Joan Venge
@Joan Venge, in real life Project requirements usually make _some_ sense. They are not arbitrary things like "no include", "no while" or "write code using only your left foot".
Daniel Daranas
+2  A: 

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?

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.

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

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.

John Kugelman
You mean the whole cpp? What if I don't need to call GetCount? Then what do I need to copy paste?
Joan Venge
Sorry I mean the whole .h file.
Joan Venge
Basically consider that the outside class has 100 functions, I just need only 1, what do I need to copy and please include a sample. I don't know whether the copied code also needs extern or not.
Joan Venge
You are right. But the requirement is "less pain" for integrations. Otherwise the file has to be included using a really long path. This is what's advised to me, so I don't know.
Joan Venge
That's the most idiotic thing I've heard.
eduffy
I should tell him that then. But before than. what if the outside class has 10 functions, and I only need GetCount. In that case, you would include only 1?
Joan Venge
You should. Stop right now and go tell him.
eduffy
You need to include the entire class definition, including all function declarations. If the class is too big to comfortably do that, there's serious design problems, and you really should learn to design better and refactor.
David Thornley
@Joan Venge: If you use the same class in more than one translation unit in the same program then each definition _must_ consist of exactly the same sequence of tokens. That is why almost everyone #includes a header file when they need to share a class definition between translation units.
Charles Bailey
+3  A: 

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

class Outside;

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

Then in 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..

sean riley
Thanks so I can't make a constructor extern?
Joan Venge
no.. the compiler would need the header file to call the constructor directly.
sean riley
You don't need `extern` for anything. `extern` is for global variables outside of any class declaration. And it doesn't work on functions either, BTW.
John Kugelman
@John Kugelman: extern works fine for function declarations. functions have external linkage by default anyway, so it's usually redundant.
Charles Bailey
+1  A: 

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."

So marking extern is for variables not classes defination/declaration

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

Ahmed Said
+5  A: 

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

Go for it and include the file!

Danra
+2  A: 

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.

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.

AShelly
+1  A: 

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).

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.

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.

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.

+3  A: 

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

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.

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.

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.

David Thornley
+4  A: 

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:

#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):

#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.

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.


Update

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

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):

#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):

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."

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():

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.

Max Lybbert
+2  A: 

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

vobject