friends and dllexport in VC++5

Is there a known problem with dllexporting and dllimporting friend functions of classes in VC++5?

I have a class with some protected members, and I declared a friend function therein to overload the operator<< for ostream. The whole class is properly dllexported. The operator<< is defined as a class-independent function:

headerfile:

class _DLL_ A {
protected:
  int a;
public:
  friend ostream & operator<<(ostream & s, A & obj);
};

implementation:

ostream & operator<<(ostream & s, A & obj) {
  return s << obj.a;
}

When I try to use this function within the DLL, everything is fine, but when I move outside the DLL and call it from an exe that includes the dll as dynamically linked library, I get a LNK2001 linker error, namely that the function is declared but not defined. what's going on?
LVL 8
MaDdUCKAsked:
Who is Participating?
 
nietodConnect With a Mentor Commented:
You're welcome.

I of course FEEL I deserve more, but as you are in the market for VC 6, you had better save your pennies.  There was a time when Microsoft's development products were being given away to encourage windows development.  Not any more...
0
 
nietodCommented:
No, I don't think there is a problem with this.  The problem probably is that the << operator is declared only in the exported class declaration, but is not exported.  

continues.
0
 
nietodCommented:
For example, if you have a header file that does

__declspec(DllExport) class SomeClass
{
   friend ostream & operator<<(ostream & s, SomeClass & obj);
};

This does not declare the ostream operator as an exported function (I think.  Now I'm beginning to to regret answering as I realize that this is not something I'm possitive of.)  I think you need to do one of two things either

__declspec(DllExport) class SomeClass
{
   friend _declspec(DllExport) ostream & operator<<(ostream & s, SomeClass & obj);
};

or

__declspec(DllExport) class SomeClass
{
   friend ostream & operator<<(ostream & s, SomeClass & obj);
};

_declspec(DllExport) ostream & operator<<(ostream & s, SomeClass & obj);

should declare the operator as an exported function.  I'm going on intuition here, but the way it is documented is that applying the _declspec(DllExport) to a class is the same as applying it to the members.  Thus, since the >> operator is not a member, the _declspec is not applied to it.  Thus you need to explicitly declare it as exported.  Give it a try and let me know if it doesn't work.
0
Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
MaDdUCKAuthor Commented:
about your last point:
other member functions of the class are exported flawlessly, it is just the friends...why?
0
 
MaDdUCKAuthor Commented:
and it did not fix the problem either...
0
 
nietodCommented:
That was my last point.  The friends are not members.  If you declare a class as beign exported, it exports the member functions of the class.  But friend functions are not member functions.  So they must be exported seperately.
0
 
nietodCommented:
I'm still suspiscios, can you post your header code?
0
 
MaDdUCKAuthor Commented:
header:
=======

/*
_DLL_ is defined to be
 - __declspec(dllimport) if the header is included outside the DLL
 - __declspec(dllexport) if the header is included inside the DLL
*/

//...

class _DLL_ Tag {
protected:
      bool const single;
//...
            
public:
//...
      friend std::ostream & operator<<(std::ostream & s, mdHtml::Tag & t);
};

//...

std::ostream & _DLL_ operator<<(std::ostream & s, Tag & t);

//...

implementation:
===============

//...

std::ostream & _DLL_ operator<<(std::ostream & s, Tag & t)
{
        // bitshift some protected members of the class onto s.
      return s;
}

//...

is this clear?

0
 
nietodCommented:
It is clear.  But you must be making some mistake that is not in your example (you've edited it.)  I have a working example.  I'll post mine for what it is worth.  If that doesn't help, you can e-mail me yours.  (nietod@theshop.net).
0
 
nietodCommented:
**********MADAPP.CPP**************
#include "maddll\maddll.h"
#include <fstream.h>
#include <windows.h>

int PASCAL    WinMain(
                HANDLE hInstance,        // Instance handle
                HANDLE hPrevInstance,    // Previous instance handle
                LPSTR lpszCommandLine,   // Command line string
                int cmdShow )        
{
   Cls A;
   fstream F;

   F << A;
   return 0;
};
*************MADDLL.H************
#ifndef _maddll
#define _maddll
#include <iostream.h>

#ifndef ExpMadDll
#define ExpMadDll _declspec(dllimport)
#endif

class ExpMadDll Cls
{
private:
   int i;
public:
   Cls();
   friend ExpMadDll ostream & operator<<(ostream & s,const Cls &c);  //******
};

#endif
**************MADDLL.CPP***************
#define ExpMadDll _declspec(dllexport)
#include "maddll.h"

Cls::Cls()
{
   i = 5;
}

ostream & __declspec(dllexport) operator<<(ostream & s,const Cls &c)
{
   s << c.i;
   return s;
}
0
 
nietodCommented:
Be aware of an inadvertant overloads.  For example, in your .header file you declare the 2nd parameter to the << operator as non-const.  (That is unusual)  Do you declare it the same way in your Dll's source code?
0
 
MaDdUCKAuthor Commented:
I'll email them to you once I cleaned up the files a little.
0
 
nietodCommented:
I'm about done for the day.  I'll be back in about 11 hours.
0
 
MaDdUCKAuthor Commented:
what is so hard to compile it? if everything fails, then extract the zip to \web\SCPCS 2.0\ of a drive and subst j: <the drive> to simulate the proper paths (or put it into j:\web\SCPCS 2.0 if you have a j: drive. Then this should work. There are a couple of path refs inside the code, but these are not evaluated until run-time...)
0
 
nietodCommented:
Well one problem is that you had long file names in there and my version of pkzip screws up the names.  But I'll get to it today.  I have one more thing to do first.
0
 
nietodCommented:
Well I finaly got it open, but I can't seem to compile it.  The problem I'm getting is that Row_Class is undefined when you create a vector<> of it.  (First you define the vector and then you define the template.  However my attempt to be move things around have produced more problems.  (I don't have a good handle on you orginization--and I had to dissable my CD (drive j) to do this and I am very impacient without my music!.)

Why would I be getting this problem whn you don't?  You don't right?
0
 
MaDdUCKAuthor Commented:
tried a dummy declare of
class Row_Class;
before the vector declaration?
0
 
nietodCommented:
A dummy won't do it.  It is verifying the class has the right members, operators constructors etc.  Since it doesn't know what the class is it assumes it is an int and then runs into problems.  If I move the class definiton before that I get other problems.  I can't image why I am getting this and you aren't.
0
 
MaDdUCKAuthor Commented:
which module is this in?

I spent a couple of hours restructuring some of the moddules because I did not like them. I will put a new project up soon, so how about you give me a path where you would like the project to sit on your hdd so that you can easily download and run it without stopping your music. I will see whether I can tweak it so it will run no probs at yours.
0
 
nietodCommented:
I get the error when compiling error.cpp--the first file it tries.  

The path doesn't matter but drive D would be nice.  or drives after K.  But at the moment I do have it so I can access j as my hard disk so if that is a problem leave it as it is.


0
 
MaDdUCKAuthor Commented:
did you get nmy email?
0
 
nietodCommented:
Yes, but I'm having trouble getting to the FTP site.  I tried this morning and again about 1/2 hour ago.  It seemed like the problem was on you end, like your server was down.  Is there a problem?
0
 
The_BrainCommented:
I would really just avoid using friend, there are disputes about its use, and a later version may drop it.  

Have you actually got a constructor? destructor.  I think that is the problem.
0
 
The_BrainCommented:
Have you actually got a constructor? destructor.  I think that is the problem. Initialise your variables as well.


I would really just avoid using friend, there are disputes about its use, and a later version may drop it.  

0
 
MaDdUCKAuthor Commented:
I have constructors and destructors. The class works fine in one unit, but the DLL export and import is causing the problem.

And I have not heard anything about the friend thingy yet. Do you have a site with additional info by any chance?
0
 
nietodCommented:
No later version of c++ will drop "friend"--ever.  The standards committee worked increadibly hard to maintain compatiblilty with legacy C code, don't you think they want to maintain compatibility with a greater quantity of C++ code?  Not to mention that friend is increadibly important.

I will look at the code a little later this morning.
0
 
The_BrainCommented:
Ok in that case nietod, I suppose that it is safe to use friends?
Well ok then.  Link errors occurs when there is a mismatch of protocols and their functions.  Just look at that maybe, I can't see anything like that in the code, but I think it is worth a look.
0
 
MaDdUCKAuthor Commented:
It seems as moving the __declspec(dllxxport) to the front of the lines fixed
the problem (don't move it for classes, i.e. a class should still be
declared as 'class __declspec(dlllexport) classname {')

nietod: thanks so much. I've upped the points to 250 (don't have much more, but if you feel like you deserve more, then I shall purchase some!)
please answer it then!
0
 
MaDdUCKAuthor Commented:
350...
because you were so nice...
0
 
nietodCommented:
you're gonna spoil me...
0
 
MaDdUCKAuthor Commented:
:-9 whatever...
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.