views:

1199

answers:

3

I have a mystery on my hands. I am trying to learn managed C++ coming from a C# background and have run into a snag. If I have a project which includes two classes, a base class Soup and a derived class TomatoSoup which I compile as a static library (.lib), I get unresolved tokens on the virtual methods in Soup. Here is the code:


Abstracts.proj

Soup.h

namespace Abstracts
{
    public ref class Soup abstract
    {
    public:
     virtual void heat(int Degrees);
    };
}

TomatoSoup.h

#include "Soup.h"

namespace Abstracts
{
    public ref class TomatoSoup : Abstracts::Soup
    {
    public:
     virtual void heat(int Degrees) override;
    };
}

TomatoSoup.cpp

#include "TomatoSoup.h"

void Abstracts::TomatoSoup::heat(int Degrees)
{
    System::Console::WriteLine("Soup's on.");
}

Main.proj

Main.cpp

#include "TomatoSoup.h"

using namespace System;

int main(array<System::String ^> ^args)
{
    Abstracts::TomatoSoup^ ts = gcnew Abstracts::TomatoSoup();

    return 0;
}


I get this link-time error on Main.proj:

1>Main.obj : error LNK2020: unresolved token (06000001) Abstracts.Soup::heat
  1. I've tried setting

    virtual void heat(int Degrees)=0;
    
  2. I've tried implementing heat in the base class

    virtual void heat(int Degrees){}
    

    and get an unreferenced formal parameter warning treated as an error.

  3. I've tried both 1 and 2 with and without the abstract keyword on the Soup class

This issue is driving me crazy and I hope to prevent it from driving other developers nuts in the future.

UPDATE: This worked with Greg Hewgill's argument-name commenting method when the TomatoSoup::heat was implemented in the header file, but the error came back when I moved the implementation to TomatoSoup.cpp. I've modified the question to reflect that.

+1  A: 

The error you are getting (LNK2020) means the linker can't find a definition for the Abstracts.Soup::heat function anywhere. When you declare the function as virtual void heat(int Degrees); the linker will expect to find the function body defined somewhere.

If you intend not to supply a function body, and require that subclasses eventually override the function, you should do as you indicated in solution 1:

virtual void heat(int Degrees) = 0;

This tells the compiler that you aren't going to implement the function. What happens when you do that?

Also, with reference to your second solution:

virtual void heat(int Degrees) {}

the compiler is telling you that you don't reference the Degrees parameter within the function. One way to avoid this warning in C++ is to not give the parameter a name:

virtual void heat(int /*Degrees*/) {}

Supplying an empty implementation is a bit different from a pure virtual (= 0) declaration, though.

Greg Hewgill
Thanks! it worked when I commented out the argument names using your technique, but now when I try to pull the implementation out of the header, I get the same linking error. I'm going to vote you up and alter the question.
brian
A: 

I don't have much CLI experience but I think you should be inheriting using public:

public ref class TomatoSoup : public Abstracts::Soup

codelogic
A: 

I think this error may have occurred because I was trying to build Abstracts.proj as a static library. When I changed it to a .DLL, everything worked fine.

I've seen mention of managed code not being supported from static libraries, but nothing official. Does anyone have a good reference that states this?

brian
Maybe good enough ==> http://groups.google.com/group/microsoft.public.dotnet.languages.vc/browse_thread/thread/69448ab54f2a9aac
demoncodemonkey
Oh man, I've been searching far and wide for any official acknowledgment of this, I wish I could vote up comments.
brian