Skip to main content
GameDev.net gamedev.net
🔒 Locked

Pure Virtual problem

Started by Kylotan Apr 22, 2000 at 2:27 PM 36 replies 2k views
Original Post
Kylotan
Kylotan
Hi, me again. I''m more questions than answers this weekend, which makes a change I get the following errors when I compile: C:\CODING\TURNBASED\appinit.cpp(47) : error C2259: ''DXSoundManager'' : cannot instantiate abstract class due to following members: C:\CODING\TURNBASED\appinit.cpp(47) : warning C4259: ''bool SoundManager:laySound(enum SoundNumber,int,int)'' : pure virtual function was not defined C:\CODING\TURNBASED\appinit.cpp(47) : error C2259: ''DXSoundManager'' : cannot instantiate abstract class due to following members: C:\CODING\TURNBASED\appinit.cpp(47) : warning C4259: ''bool SoundManager:laySound(enum SoundNumber,int,int)'' : pure virtual function was not defined Line 47 is: theSoundManager = new DXSoundManager(); Now, I understand what these errors are and what they mean. What I don''t get is (a) Why I am getting the error - DXSoundManager (a derived class of SoundManager) certainly does have the named function, both in the class definition and in the accompanying CPP file. (b) Why I would get the error twice! And in one line. All my headers have inclusion guards. I just wondered if anyone had seen this before and had any idea what I was doing wrong. I have too much code to post it all, and I was hoping this was one of those weird situations with a certain way to fix it.
Erik Post
Erik Post
It''s a bit hard to tell what''s going on without knowing what your DXSoundManager and SoundManager look like... So, if you could post (pieces of) the interface of those classes, we could tell some more.

Erik
Queasy
Queasy
I have gotten this before, but it was because my base class still had an undefed virtual in it (like your OverlaySound fn [or whatever it''s called, i can''t read it because it shows up as some sort of face on this msg board )

If you''re positive you''ve defined it, then check for stupid errors, ex. did you define it as
BOOL OverlaySound(blah) {
}
or BOOL DxSoundManager::OverlaySound(blah) {
}

and was it defined in the class fn as a proper member? [ex. w/o the virtual keyword, etc).

I know this sounds trivial and stuff, but hey, it''s happened to me before

or maybe even try
theSoundManager = new DxSoundManager; //ie. w/o ()s

Jonathan Makqueasy gamesgate 88[email=jon.mak@utoronto.ca]email[/email]
null_pointer
null_pointer
I''ve run into this a lot lately, but it''s just an incorrect declaration or definition somewhere. Even a slight difference, such as constness, will cause that error. Try copying and pasting the function declaration from the base class into the derived class, so it matches exactly (removing the " = 0"). Then copy and paste that into the .cpp file as well for the definition, making the changes necessary to make it a definition.



- null_pointer
Sabre Multimedia
Kylotan
Kylotan
Ok, here''s some copy and pasting. Please sign the NDA before reading further

In soundmanager.h:

class SoundManager
{
public:
// Interface for derived classes to implement
SoundManager();
virtual ~SoundManager();

// Sets it up
virtual bool Init() = 0;
// Knocks it down
virtual bool Shutdown() = 0;

// Plays a sound
virtual bool PlaySound(SoundNumber num, int volume, int pan) = 0;

// Member functions
bool IsSetup() const;

protected:
// SOME IRRELEVANT STUFF HERE
};

in dxsoundmanager.h:

class DXSoundManager : public SoundManager
{
public:
// Inherited interface ////////////////////
~DXSoundManager();
bool Init();
bool Shutdown();

bool PlaySound(SoundNumber num, int volume, int pan);


private:
// DX specific members
};

In dxsoundmanager.cpp

bool DXSoundManager:: PlaySound(SoundNumber num, int volume, int pan)
{
return false; // just a stub function for now
}


I am probably just overlooking something stupid as I''ve been staring at this code (and my annoying binary streams problem) for hours now...
axelp
axelp
Did you actually create an implementation of the virtual function? I believe you have to do something like

class A: {
public: F() = 0;
}

A::F()
{
}

so actually have an (empty) implementation.
--- axelP
Kylotan
Kylotan
quote:
Original post by axelp

Did you actually create an implementation of the virtual function?


I don''t believe an abstract base class needs to have its pure virtual functions to have a body. In fact, 99% of the time I don''t think you''d want it to have one. Am I right?

Rock2000
Rock2000
A class needs only 1 pure virtual function to be abstract, and I''ve never seen a body for a pure virtual member (though I''ve never thought about it).

As for the error, the only thing I''d check is to make sure your SoundNumber is referencing the same typedef. I assume it is, but I don''t see anything else that would cause a problem. (Or try to replace it with an int, and see if maybe the compiler has a problem with the enum in this case)

Rock
MadKeithV
MadKeithV
Well the obvious error from the code you''ve posted is that you STILL haven''t provided a body for the two pure virtual functions in the abstract base class.

Two things:
1. The implementations of the pure virtual functions should be normal virtual functions most of the time.

2. You NEED to provide a body for every pure virtual function in your class derived from the abstract base class, unless you want to use your derived class as another abstract base class.


#pragma DWIM // Do What I Mean!
~ Mad Keith ~
**I use Software Mode**
It's only funny 'till someone gets hurt.And then it's just hilarious.Unless it's you.
Erik Post
Erik Post
Weird... Did you provide an implementation for all inherited virtual functions in the derived class?

What type is theSoundManager? Is it a pointer to a SoundManager, or a pointer to DXSoundManager?

If a function is defined as pure virtual (ie with = 0), then an implementation doesn''t need to be provided for the base class, as the ''= 0'' part indicates that it''s a virtual function without an implementation. It''s used solely to be overrided by a derived class.

Erik
Kylotan
Kylotan
MadKeithV - I have provided bodies for all the virtual functions declared in the base class. I just didn''t post them as I considered them out of the scope of the problem. And if they -were- the problem, it would still indicate a compiler bug if it reports something else as being wrong. Sorry for the confusion.

Rock2000 and Erik - as far as I know, it is valid to provide an implementation for a pure virtual function. It doesn''t mean you can instantiate it, but it does mean you can store common code there. I think you can call it with the syntax BaseClassName::FuncName(); But this is not relevant as I am not doing such a thing

Erik - theSoundManager is a SoundManager*, ie. pointer to SoundManager. This is my abstract interface, and I derive specific implementations from it (so far, just DXSoundManager). The idea being that, apart from making portability much easier, eventually the user should be able to choose at runtime between DirectSound or standard multimedia functions, for example.

Rock2000 - I swapped all the SoundNumber instances for ints, and... I still get the error. It just says int in the errors and warnings where it used to say ''enum SoundNumber''.

I may be getting arrogant here, but I can''t help thinking this is perhaps a compiler bug? Especially since it reports the error twice in one line??
crazy166
crazy166
i always declare the inherited functions to be virtual also, so in your DXSoundManager you should have
virtual bool PlaySound(...).

i can''t remember if that gives a compiler error and i have to take it out, or if it works, but i always do that first for some reason.



crazy166
some people think i'm crazy, some people know it
axelp
axelp
If you remove the =0, does it still give any warnings?


--- axelP
Rock2000
Rock2000
Hmmm, if it was an enum problem I''d believe it was the compiler. Using just ints, I find it hard to believe the compiler is messing it up (VC?).

I don''t usually do this (I''m a lazy, lazy man), but if you want, try to strip out all the proprietary, NDA stuff (), and even just replace the function bodies with return calls, and send me the 4(?) h/cpp files. I''m curious as to what the compiler is doing.

Rock
Rock2000
Rock2000
Actually, I just thought of 1 other thing you can check if this is for Windows. I had this problem way back, and I screamed and screamed at the Win API once I found it. Try to rename your PlaySound functions something else. Windows has a VERY BAD habit of defining the most basic names for its use. It may be replacing your PlaySound with PlaySoundA or something stupid. That is one of my biggest pet peaves (big APIs that use the most common names. They should all start with some Window''s signiture such as W or C or whatever)

Rock
null_pointer
null_pointer
I don't understand what is wrong -- must be something in your other code. The code you posted earlier works fine. Here's the entire console app I built and tested with it:


// Test2.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include


enum SoundNumber {};


class SoundManager
{
public:
// Interface for derived classes to implement
SoundManager() {};
virtual ~SoundManager() {};

// Sets it up
virtual bool Init() = 0;
// Knocks it down
virtual bool Shutdown() = 0;

// Plays a sound
virtual bool PlaySound(SoundNumber num, int volume, int pan) = 0;

// Member functions
bool IsSetup() const;

protected:
// SOME IRRELEVANT STUFF HERE
};


class DXSoundManager : public SoundManager
{
public:
// Inherited interface ////////////////////
~DXSoundManager() {};
bool Init() { return false; };
bool Shutdown() { return false; };

bool PlaySound(SoundNumber num, int volume, int pan);


private:
// DX specific members
};


bool DXSoundManager:: PlaySound(SoundNumber num, int volume, int pan)
{
return false; // just a stub function for now
}


int main(int argc, char* argv[])
{
DXSoundManager MySoundManager;
return 0;
}



I also included Windows.h, which someone said might be the problem. Actually, that only happens with classes, and not functions of classes, because functions of classes do not have global scope and thus can't collide with the Windows functions, which do have global scope.

Also, it is most definitely not a compiler bug, as I'm using VC 6.0 without problems. As I said before, I use pure virtual functions all the time, and it is always a syntax error that causes the problem. Look for something else besides the source you posted. Oh, just remembered -- did you forget to add the DXSoundManager.cpp file to the project?




- null_pointer
Sabre Multimedia


Edited by - null_pointer on 4/25/00 7:19:56 AM
Rock2000
Rock2000
You have too much faith in Microsoft. While it IS bad enough they even have common function/names, this is much worse than that. I''ve been thinking about it, and I (practically) guarantee that Microsoft is mangling the function name. They have #defines, that will convert PlaySound to PlaySoundA, so it isn''t a matter of function conflicts here.

If the cpp file includes windows.h, and the header doesn''t, than the implemtation function name gets changed to PlaySoundA, and PlaySound is still undefined.

Rock
null_pointer
null_pointer
Rock2000: Who would include windows.h in the .cpp file and not in the .h file? That is a bad coding setup... Also, I moved the #include statement for windows.h between the PlaySound declaration and definition (same thing as splitting files), and it causes a compiler error with PlaySoundA, which is much different than the linker error that Kylotan copied right out of the build output window.

This is the error I got, if you want to see it:

quote:
Original post by MSVC 6.0

compiling...
Test2.cpp
c:\PROGRAM FILES\MICROSOFT VISUAL STUDIO\MYPROJECTS\Test2\Test2.cpp(53) : error C2039: ''PlaySoundA'' : is not a member of ''DXSoundManager''
c:\PROGRAM FILES\MICROSOFT VISUAL STUDIO\MYPROJECTS\Test2\Test2.cpp(33) : see declaration of ''DXSoundManager''
Error executing cl.exe.

Test2.exe - 1 error(s), 0 warning(s)







- null_pointer
Sabre Multimedia
Josh
Josh
>> Who would include windows.h in the .cpp file and not in the .h file? That is a bad coding setup...

::Raises hand:: I would (do). It is not bad coding setup, it makes for quicker compile times. Sometimes you want to hide the win32 code from the interface but you need it for the implementation. Why include something you don't need?

Also, null_pointer, your code isn't exactly identical to Kylotan's. When you declared your variable, you did so like this:

DXSoundManager MySoundManager;

Kylotan did it like this:

theSoundManager = new DXSoundManager();

Not exactly the same thing. Try changing it and see if it still compiles correctly. If it does not, then I would agree with those who say that it is the compiler.


Josh
http://www.jh-software.com

Edited by - Josh on 4/25/00 5:28:17 PM
Joshhttp://www.jh-software.com

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.