"Cannot instantiate abstract class"

Get answers to all your basic programming questions. No Ogre questions, please!
N_K
Greenskin
Posts: 115
Joined: Wed Dec 07, 2011 9:05 pm
x 4

"Cannot instantiate abstract class"

Post by N_K »

Hello all.

Although kind of Ogre-related, it's still a general coding issue (or more likely a proof of my incompetence in anything object-oriented), so I thought I'd post
it here.

I try to get OgreNewt working with VS2010. It's not going well. I was able to build the wrapper itself after commenting out a function that doesn't seems to be used in any of the demos and calls to a function that has been removed from Newton a few versions ago. I was able to build some of the demos, too. But when I try to build any of the demos which use some kind of raycasting, I get to a part I can't figure out.

So the compiler fails with this:

Code: Select all

1>OgreNewtonApplication.cpp(139): error C2259: 'OgreNewt::BasicRaycast' : cannot instantiate abstract class
1>          due to following members:
1>          'bool OgreNewt::Raycast::userCallback(OgreNewt::Body *,OgreNewt::CollisionPtr &,Ogre::Real,const Ogre::Vector3 &,int)' : is abstract
1>          c:\src-vs\ogrenewt\inc\OgreNewt_RayCast.h(65) : see declaration of 'OgreNewt::Raycast::userCallback'
After taking a look at the offending header file, I've found two classes: Raycast and BasicRaycast. Both of these classes have functions named userCallback, but (obviously) they are different, the one in BasicRaycast takes 4 arguments, while the other takes 5. And at this point, I gave up. I don't get what exactly is the problem, since as far as I know, it's not illegal to have functions with the same name in different classes. Doing a google search for this error message didn't help much, the explanation in most forums were as cryptic as the message itself. So, could somebody enlighten me about this, please?

And the most important question is, how come this code builds fine with GCC and VS9, but not with VS10?
User avatar
jacmoe
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 20570
Joined: Thu Jan 22, 2004 10:13 am
Location: Denmark
x 179

Re: "Cannot instantiate abstract class"

Post by jacmoe »

First of all, what is an abstract class?

It is a class which has at least one pure virtual function.

This means that deriving classes must implement that function, otherwise the compiler will complain.

See this:
http://msdn.microsoft.com/en-us/library/c8whxhf1.aspx

I haven't looked at OgreNewt, so I don't know the class graph, so what is the relationship between Raycast and BasicRaycast ?
Does one of them inherit the other?
Does any of those classes define/implement the function?

Or, does the sample inherit from it, and implement the function?

It looks like it doesn't.

Whatever inherits from OgreNewt::BasicRaycast (I guess it's the OgreNewtonApplication?) needs to declare and define 'bool OgreNewt::Raycast::userCallback(OgreNewt::Body *,OgreNewt::CollisionPtr &,Ogre::Real,const Ogre::Vector3 &,int)'.

That's all I know. ;)
/* Less noise. More signal. */
Ogitor Scenebuilder - powered by Ogre, presented by Qt, fueled by Passion.
OgreAddons - the Ogre code suppository.
N_K
Greenskin
Posts: 115
Joined: Wed Dec 07, 2011 9:05 pm
x 4

Re: "Cannot instantiate abstract class"

Post by N_K »

Thanks for your explanation, and for the link. Now I understand a few things a little better.

After studying these source files, I'll try to explain what's going on, but I'm a bit confused now.

OgreNewtonApplication does not call userCallback directly. It only creates a Newton "raycast query" through the OgreNewt::BasicRaycast class. The exact code looks like this:

Code: Select all

OgreNewt::BasicRaycast castRay (m_World, start, end, true);
The userCallback function is used internally by this class.

[EDIT] I think I'll post the actual header, since my explanation was a complete mess. Here is it (I've removed the comments and the include/define parts to make it smaller):

Code: Select all

namespace OgreNewt
{
    class _OgreNewtExport Raycast
    {
	public:
	    Raycast();
	    virtual ~Raycast();

	    void go(const OgreNewt::World* world, const Ogre::Vector3& startpt,
		    const Ogre::Vector3& endpt);

	    virtual bool userPreFilterCallback(OgreNewt::Body* body)
	    {
		return true;
	    }

	    virtual bool userCallback(OgreNewt::Body* body,
		    OgreNewt::CollisionPtr& col, Ogre::Real distance,
		    const Ogre::Vector3& normal, int collisionID) = 0;

	    friend float
	    CollisionPrimitives::TreeCollision::newtonRayCastCallback(
		    const NewtonBody* body, const NewtonCollision* col,
		    float distance, float *normal, int faceId, void *userData);
	protected:
	    OgreNewt::Body *mLastBody;
	    OgreNewt::CollisionPtr mLastCollision;
	    bool mBodyAdded;

	private:
	    static float _CDECL newtonRaycastFilter(const NewtonBody* body,
		    const float* hitNormal, int collisionID, void* userData,
		    float intersetParam);

	    static unsigned _CDECL newtonRaycastPreFilter(
		    const NewtonBody* body, const NewtonCollision* collision,
		    void* userData);
    };

    class _OgreNewtExport BasicRaycast: public Raycast
    {
	public:
	    class _OgreNewtExport BasicRaycastInfo
	    {
		public:
		    BasicRaycastInfo();
		    ~BasicRaycastInfo();

		    Ogre::Real getDistance()
		    {
			return mDistance;
		    }
		    ;
		    OgreNewt::Body* getBody()
		    {
			return mBody;
		    }
		    ;
		    int getCollisionId()
		    {
			return mCollisionID;
		    }
		    ;
		    Ogre::Vector3 getNormal()
		    {
			return mNormal;
		    }
		    ;
		    Ogre::Quaternion getNormalOrientation()
		    {
			return OgreNewt::Converters::grammSchmidt(mNormal);
		    }
		    ;

		    Ogre::Real mDistance;
		    OgreNewt::Body* mBody;
		    int mCollisionID;
		    Ogre::Vector3 mNormal;

		    bool operator<(const BasicRaycastInfo& rhs) const
		    {
			return mDistance < rhs.mDistance;
		    }
	    };

	    BasicRaycast();
	    BasicRaycast(const OgreNewt::World* world,
		    const Ogre::Vector3& startpt, const Ogre::Vector3& endpt,
		    bool sorted);

	    void go(const OgreNewt::World* world, const Ogre::Vector3& startpt,
		    const Ogre::Vector3& endpt, bool sorted);

	    ~BasicRaycast();
		
	    bool userCallback(Body* body, Ogre::Real distance,
		    const Ogre::Vector3& normal, int collisionID);

	    int getHitCount() const;
		
	    BasicRaycastInfo getInfoAt(unsigned int hitnum) const;

	    BasicRaycastInfo getFirstHit() const;

	private:
	    typedef std::vector<BasicRaycastInfo> RaycastInfoList;

	    RaycastInfoList mRayList;
    };

}
fd9_
Halfling
Posts: 64
Joined: Wed Aug 20, 2008 9:20 pm
x 22

Re: "Cannot instantiate abstract class"

Post by fd9_ »

I'm not familiar with OgreNewt, but without knowing any other information I would say this is a bug.

BasicRayCast::userCallBack and RayCast::userCallBack need to have the same declaration (i.e, the same parameters). Try modifying BasicRayCast::userCallBack so that it takes a OgreNewt::CollisionPtr& as the second parameter, and then re-build:

Code: Select all

bool userCallback(OgreNewt::Body* body,
          OgreNewt::CollisionPtr& col, Ogre::Real distance,
          const Ogre::Vector3& normal, int collisionID);
N_K
Greenskin
Posts: 115
Joined: Wed Dec 07, 2011 9:05 pm
x 4

Re: "Cannot instantiate abstract class"

Post by N_K »

That's it, you've fixed it! Thank you. I knew it was something trivial, but I was unable to figure this out, no matter what.