• Create Account

Compiler says class has no constructor while it actually has one

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

20 replies to this topic

#1lucky6969b  Members

1185
Like
0Likes
Like

Posted 28 May 2013 - 09:50 PM

activity = new Idle(this, NULL);


class Idle : public Activity

{

private:

float mTimeInIdle;

public:

Idle() : mTimeInIdle(0)    { }

Idle(Objects *actor, Goods *target) : Activity(actor, target)

{

}


Error    1    error C2514: 'Idle' : class has no constructors    d:\jacky\documents\visual studio 2010\projects\perfectsim\perfectsim\perfectsim\Objects\Objects.h    43    1    PerfectSim

The activity = new Idle(this, NULL) line is located inside the Objects::Objects(...)  constructor.

Would it be caused by some cyclic dependencies? How do I go about resolving it?

Thanks

Jack

5832
Like
3Likes
Like

Posted 28 May 2013 - 11:15 PM

Sounds like you only forward declared the class and didn't include the full class definition (include the header that defines the class in the source files that call new Idle()).

If that gives you a circular dependency you will have to look at your class dependencies (you could make a class factory that is responsible for returning new Idle objects, for example).

"Most people think, great God will come from the sky, take away everything, and make everybody feel high" - Bob Marley

#3lucky6969b  Members

1185
Like
0Likes
Like

Posted 28 May 2013 - 11:51 PM

I put everything inside header files. like Objects.h and Idle.h

#pragma once

#include "..\SkinnedMesh\skinnedMesh.h"
#include "..\Activities\Activity.h"
#include "DetourNavMeshQuery.h"
#include "MotiveBase.h"

//#include "..\myDX9Widget.h"

class myDX9Widget;
class Idle;

class Objects
{
public:
Objects() : m_pAnimCtrl(0), energy(0) { }

Objects(SkinnedMesh* _mesh) : m_pAnimCtrl(0)
{
SetPos(D3DXVECTOR3(0,0,0));
SetRot(D3DXVECTOR3(0,0,0));
SetRotCenter(D3DXVECTOR3(0,0,0));
SetScale(D3DXVECTOR3(1,1,1));
SetScaleCenter(D3DXVECTOR3(1,1,1));

D3DXQUATERNION quat;
D3DXQuaternionIdentity(&quat);

SetRotQuat(quat);

if (_mesh->GetMasterAnimCtrl() != NULL)
{
_mesh->GetMasterAnimCtrl()->CloneAnimationController(
_mesh->GetMasterAnimCtrl()->GetMaxNumAnimationOutputs(),
_mesh->GetMasterAnimCtrl()->GetMaxNumAnimationSets(),
_mesh->GetMasterAnimCtrl()->GetMaxNumTracks(),
_mesh->GetMasterAnimCtrl()->GetMaxNumEvents(),
&m_pAnimCtrl);
}

activity = new Idle(this, NULL);

mesh = _mesh;
}


Edited by lucky6969b, 28 May 2013 - 11:51 PM.

5832
Like
4Likes
Like

Posted 28 May 2013 - 11:59 PM

Then you need to include Idle.h in objects.h. You can't just forward declare it. You should use a cpp file for the implementations of the functions though and just declare them in the class definition, you are going to end up with problems with dependencies soon if you carry on with the "all in a header" approach.

If Idle needs to use member functions/variables in Objects and vice versa you are going to end up with a circular dependency which will require separation of the function body from the in-class declaration.

"Most people think, great God will come from the sky, take away everything, and make everybody feel high" - Bob Marley

#5lucky6969b  Members

1185
Like
0Likes
Like

Posted 29 May 2013 - 12:23 AM

Now that I've included Idle.h in Objects.h

so that Objects should see everything in idle, that's point 1

Point 2, idle can't see everything in Objects. So I forward declare it, otherwise, I have a circular references, Objects->Idle and Idle->Objects

How do I make Idle see Objects so I won't get the following errors:

Error    1    error C2027: use of undefined type 'Objects'    d:\jacky\documents\visual studio 2010\projects\perfectsim\perfectsim\perfectsim\Activities\Idle.h    29    1    PerfectSim
Error    3    error C2027: use of undefined type 'Objects'    d:\jacky\documents\visual studio 2010\projects\perfectsim\perfectsim\perfectsim\Activities\Idle.h    33    1    PerfectSim
Error    10    error C2027: use of undefined type 'Objects'    d:\jacky\documents\visual studio 2010\projects\perfectsim\perfectsim\perfectsim\activities\Idle.h    29    1    PerfectSim

#6Olof Hedman  Members

5703
Like
1Likes
Like

Posted 29 May 2013 - 12:57 AM

You can break the circular dependency if you split your implementation and declaration into .cpp and .h-files

Only declare the classes in the header-files, no method implementations.

You can have only a forward declaration in the .h-file if you only have pointers to the classes in the .h-file

Then include the full header in the cpp-file to be able to call its methods.

#7BitMaster  Members

8647
Like
2Likes
Like

Posted 29 May 2013 - 12:59 AM

I put everything inside header files.

That simply will not work in C++ in general. Any code in Objects.h that needs to see more than the forward declaration should be moved into an implementation file which can see the whole interface of Idle.

There are languages which do not require (or even allow) the separation between header and implementation that C++ usually requires, but I would suggest switching languages if you really want it that badly. Trying to force it on C++ will just lead to pain and suffering.

#8lucky6969b  Members

1185
Like
0Likes
Like

Posted 29 May 2013 - 01:50 AM

Please do a quick check on my coding

Activity.h

#include <string>

class Idle;
class Objects;
class Goods;

class Activity
{
public:
Objects *Actor;
Goods *Target;
Activity() : Actor(0), Target(0) { }
Activity( Objects* actor, Goods* target )
{
Actor = actor;
Target = target;
}

virtual bool OnUpdate(float seconds) = 0;

void Update(float seconds);

Activity *FindBestActivity(Objects *actor);

std::string ToString();

};


Idle.h

#include "Activity.h"

#define MAX_IDLE_TIME 8
#define ACTIVITY_IDLE_ENERGY 1.0

class Objects;
class Activity;

class Idle : public Activity
{
private:
float mTimeInIdle;

public:
Idle() : mTimeInIdle(0)    { }
Idle(Objects *actor, Goods *target);

bool OnUpdate(float seconds);

};


idle.cpp

#include "Idle.h"

Idle::Idle(Objects* actor, Goods *target) : Activity(actor, target)
{

}

bool Idle::OnUpdate(float seconds)
{

mTimeInIdle += seconds;
if (mTimeInIdle >= MAX_IDLE_TIME)
{
Actor->activity = FindBestActivity(Actor);
}

Actor->energy += ACTIVITY_IDLE_ENERGY * seconds;
return false;
}

Error    1    error C2027: use of undefined type 'Objects'    D:\Jacky\Documents\Visual Studio 2010\Projects\PerfectSim\PerfectSim\PerfectSim\Activities\Idle.cpp    16    1    PerfectSim
Error    3    error C2027: use of undefined type 'Objects'    D:\Jacky\Documents\Visual Studio 2010\Projects\PerfectSim\PerfectSim\PerfectSim\Activities\Idle.cpp    20    1    PerfectSim
Error    2    error C2227: left of '->activity' must point to class/struct/union/generic type    D:\Jacky\Documents\Visual Studio 2010\Projects\PerfectSim\PerfectSim\PerfectSim\Activities\Idle.cpp    16    1    PerfectSim
Error    4    error C2227: left of '->energy' must point to class/struct/union/generic type    D:\Jacky\Documents\Visual Studio 2010\Projects\PerfectSim\PerfectSim\PerfectSim\Activities\Idle.cpp    20    1    PerfectSim

I've moved everything into implementation file. Here now are what I've got.

Thanks

#9BitMaster  Members

8647
Like
1Likes
Like

Posted 29 May 2013 - 02:13 AM

From quickly glancing over it the problem seems to be the obvious failure to include Activity.h in Idle.cpp.

#10Ectara  Members

3097
Like
1Likes
Like

Posted 29 May 2013 - 04:01 AM

From quickly glancing over it the problem seems to be the obvious failure to include Activity.h in Idle.cpp.

Idle.cpp includes Idle.h, which in turn includes Activity.h.

It seems that the problem is that you're dereferencing the Objects class in the Idle::OnUpdate() method, while you only have a forward declaration. You'll need to include the header for all objects that you will need more than a pointer or reference to in order to use them. If this causes a circular dependency or circular header-inclusion, then the hierarchy of files needs to be fixed.

Edited by Ectara, 29 May 2013 - 04:04 AM.

#11Khatharr  Members

7697
Like
1Likes
Like

Posted 29 May 2013 - 06:41 PM

Not a bug, but what happened here?
    Activity() : Actor(0), Target(0) { }
Activity( Objects* actor, Goods* target )
{
Actor = actor;
Target = target;
}


void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

#12ChaosEngine  Members

4769
Like
1Likes
Like

Posted 29 May 2013 - 10:42 PM

Not a bug, but what happened here?

    Activity() : Actor(0), Target(0) { }
Activity( Objects* actor, Goods* target )
{
Actor = actor;
Target = target;
}

Default constructor sets Actor and Target to NULL?

OP, you need to include objects.h and activity.h in idle.cpp

if you think programming is like sex, you probably haven't done much of either.-------------- - capn_midnight

#13Khatharr  Members

7697
Like
1Likes
Like

Posted 30 May 2013 - 06:35 PM

Not a bug, but what happened here?

    Activity() : Actor(0), Target(0) { }
Activity( Objects* actor, Goods* target )
{
Actor = actor;
Target = target;
}

Default constructor sets Actor and Target to NULL?

OP, you need to include objects.h and activity.h in idle.cpp

Thank you for that...

There's two constructors there. I was asking why he uses initializers in one and manual assignments in the other.

void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

#14Ectara  Members

3097
Like
1Likes
Like

Posted 30 May 2013 - 10:18 PM

Not a bug, but what happened here?

    Activity() : Actor(0), Target(0) { }
Activity( Objects* actor, Goods* target )
{
Actor = actor;
Target = target;
}

Default constructor sets Actor and Target to NULL?

OP, you need to include objects.h and activity.h in idle.cpp

Thank you for that...

There's two constructors there. I was asking why he uses initializers in one and manual assignments in the other.

My guess is the assumption that only constants can be used in initializer lists.

#15lucky6969b  Members

1185
Like
0Likes
Like

Posted 31 May 2013 - 03:47 AM

The hierarchy is as follows

Objects.h includes Idle.h

Idle.h includes activity.h

The problem I am having is Objects would instance Idle, which derives from Activity

And Idle has a pointer referencing Objects as well in turn.

Would that be a problem if I instance Idle in the header file called Objects.h, not in the implementation file as well

Thanks

Jack

Edited by lucky6969b, 31 May 2013 - 03:53 AM.

#16lucky6969b  Members

1185
Like
0Likes
Like

Posted 31 May 2013 - 04:08 AM

Not a bug, but what happened here?

    Activity() : Actor(0), Target(0) { }
Activity( Objects* actor, Goods* target )
{
Actor = actor;
Target = target;
}

Default constructor sets Actor and Target to NULL?

OP, you need to include objects.h and activity.h in idle.cpp

Thank you for that...

There's two constructors there. I was asking why he uses initializers in one and manual assignments in the other.

What is the general practice when confronting with this situation?

Thx

Jack

#17JTippetts  Moderators

12317
Like
2Likes
Like

Posted 31 May 2013 - 05:24 AM

What is the general practice when confronting with this situation?

 Activity( Objects* actor, Goods* target ) : Actor(actor), Target(target)
{
}


It seems you have a misunderstanding about compilation units and forward-declaration in general here. From your errors, for example...
error C2027: use of undefined type 'Objects'    D:\Jacky\Documents\Visual Studio 2010\Projects\PerfectSim\PerfectSim\PerfectSim\Activities\Idle.cpp    16    1    PerfectSim

...the Idle.cpp compilation unit has no idea what the Objects class looks like; which is, of course, because Idle.cpp only #includes Idle.h. Idle.h only #includes Activity.h. Neither of these include Objects.h, so the compiler has no way of knowing what Objects looks like, what members or methods are accessible, or even that it exists as a class.

Forward declaration is used to inform the compiler that there is a class called Object, but it still doesn't give the compiler any indication of what that class looks like. It is sufficient to forward declare a class in a header if, for example, you use a pointer to that class somewhere in another class definition; but if you actually want to call any methods or reference any members of that class, then a forward declaration isn't sufficient and the compiler will, at that point, need the full class declaration from the class header to be included.

Now, you say that Object.h includes Idle.h, which includes Activity.h, so including Object.h into the Idle.cpp compilation unit would cause a problem, since Idle.h is already explicitly included, resulting in a multiple declaration. Removing the include of Idle.h and just including Object.h instead would solve it, but problems of multiple definition like this are why people commonly use what are called include guards, either the pre-processor directive #pragma once or an #ifndef structure like this:
#ifndef IDLE_H
#define IDLE_H
// Class declaration here
#endif

Using pre-processor directives like this means that you can safely include a header multiple times in a compilation unit, but it will only actually be included once. If Activity.h, Idle.h and Object.h were all properly equipped with include guards, then you can safely include them wherever needed, without worrying about redeclaration errors.

Watch out for circular dependencies. If you have something like this:
// Foo.h
#ifndef FOO_H
#define FOO_H
#include "Bar.h"

class Foo
{
public:
Bar bar_;
};
#endif

// Bar.h
#ifndef BAR_H
#define BAR_H
#include "Foo.h"

class Bar
{
public:
Foo foo_;
};
#endif

then you have a problem. This sort of code structure is not allowed. If you study the nesting you should see why. Foo contains an instance of Bar, which contains an instance of Foo, which contains an instance of Bar, and so on until out-of-memory exception, infinity, or the heat-death of the universe, whichever comes first. It is, however, legal to achieve the same with pointers, as you seem to be doing despite your statements that Objects.h instanced Idle:
// Foo.h
#ifndef FOO_H
#define FOO_H

#include "Bar.h"

class Foo
{
public:
Bar *bar_;
};

#endif

//Bar.h
#ifndef BAR_H
#define BAR_H

#include "Foo.h"

class Bar
{
public:
Foo *foo_;
};
#endif

Doing it this way is okay. Note that if you didn't have include guards, though, it would fail because including Foo.h would also include Bar.h which would in turn include Foo.h, which would again include Bar.h, and so on, yada yada yada, heat death. But the include guards mean that once the set of declarations enclosed by the guards have been processed, they won't be processed again, so including Foo.h will include Bar.h, which will try to include Foo.h but since it has already been included it amounts to a no-op and Bar.h will not be included again.

This, however, is not really recommended. If the class Foo is only ever referred to in pointer definitions in Bar.h, and Bar is only ever referred to in pointer definitions in Foo.h, then there is no need for either header to explicitly include the other. This is where forward declarations come in:
// Foo.h
#ifndef FOO_H
#define FOO_H

class Bar;
class Foo
{
public:
Bar *bar_;
};
#endif

// Bar.h
#ifndef BAR_H
#define BAR_H

class Foo;
class Bar
{
public:
Foo *foo_;
};
#endif

If nothing inside the Foo.h header needs to know what Bar looks like (ie, what methods or members it has) but just has to be able to deal with a pointer to Bar, then it is preferred to merely forward declare Bar rather than explicitly include Bar.h. This removes a compile-time dependency between the two modules. If the two headers explicitly include each other, and a change is made to one header, then any compilation unit where either of those headers is included will end up being re-compiled even if it wouldn't normally be necessary. By removing the explicit inclusion and using forward declaration instead, you can skip some needless recompiling. Note, however, that if the Foo.cpp compilation unit makes any kind of use of the Bar pointer member (ie, using it to call any Bar methods or access any Bar members) then Foo.cpp will need to include Bar.h so that the compiler knows what it looks like. Similarly with Bar.cpp including Foo.h.

Forward declaration is also useful for setting up circular pointer-based dependencies that occur within the same header:
// FooBar.h
#ifndef FOOBAR_H
#define FOOBAR_H

class Bar;
class Foo
{
public:
Bar *bar_;
};

class Bar
{
public:
Foo *foo_;
};


In this example, when Foo is declared, Bar hasn't yet been declared so the only way Foo has of knowing that Bar is even a class type is through the forward declaration of Bar.

Now, say you want to change the pointer to Bar that Foo holds into an actual instance of Bar:
// FooBar.h
#ifndef FOOBAR_H
#define FOOBAR_H

class Bar;
class Foo
{
public:
Bar bar_;
};

class Bar
{
public:
Foo *foo_;
};

#endif

This won't work, because since Foo is dealing with an instance of Bar rather than just a pointer to it, forward declaration is no longer sufficient. The compiler needs to know what Bar looks like, in order to know how big a piece of memory to allocate for it inside the Foo memory structure. Similarly, if any inlined functions declared in the class declaration of Foo call bar_'s methods, then forward declaration is no longer sufficient. This won't work:
// FooBar.h
#ifndef FOOBAR_H
#define FOOBAR_H

class Bar;
class Foo
{
public:
Bar *_;

inline void baz()
{
if(bar_) bar_->qux();
}
};

class Bar
{
public:
Foo *foo_;

void qux();
};
#endif

At the point of defining the method Foo::baz, the inline function definition explicitly calls the method Bar::qux, meaning that at that point the compiler will need to know what Bar looks like, and the forward declaration isn't sufficient. In this case you'll probably want to forego defining any methods, inline or otherwise, inside the header file and put them in the compilation unit instead. Granted, reversing the order that Foo and Bar appear, and forward declaring Foo for Bar's declaration, would solve the issue but it wouldn't solve the problem presented here:
// FooBar.h
#ifndef FOOBAR_H
#define FOOBAR_H

class Bar;
class Foo
{
public:
Bar * bar_;

inline void baz()
{
if(bar_) bar_->qux();
}
};

class Bar
{
public:
Foo *foo_;

inline void qux()
{
if(foo_) foo_->baz();
}
};
#endif

... which, ignoring for a moment the infinite recursion loop, simply wouldn't compile given the insufficiency of the forward declaration.

So just remember: use forward declaration if you only need to know if a class exists but don't care what it looks like, but explicitly include the class header file if you need to know what it looks like. Use include guards to prevent multiple declarations of classes. And sorry for the long post; it kind of got away from me.

Edited by JTippetts, 31 May 2013 - 05:56 AM.

#18Brother Bob  Moderators

10107
Like
1Likes
Like

Posted 31 May 2013 - 05:28 AM

Not a bug, but what happened here?

    Activity() : Actor(0), Target(0) { }
Activity( Objects* actor, Goods* target )
{
Actor = actor;
Target = target;
}
Default constructor sets Actor and Target to NULL?

OP, you need to include objects.h and activity.h in idle.cpp

Thank you for that...

There's two constructors there. I was asking why he uses initializers in one and manual assignments in the other.

What is the general practice when confronting with this situation?
Thx
Jack
Always use the initializer list, unless you have a specific reason NOT to. The quoted code above does not have any reason not to use it so both constructors should use the initializer list.

#19lucky6969b  Members

1185
Like
0Likes
Like

Posted 01 June 2013 - 04:01 AM

One error left.

activity = new Idle(this, NULL);


Error    1    error C2514: 'Idle' : class has no constructors    d:\jacky\documents\visual studio 2010\projects\perfectsim\perfectsim\perfectsim\Objects\Objects.h    44    1    PerfectSim

The strange thing was I already had my constructor set in place.

#pragma once

#include "Activity.h"
#include "..\Objects\Objects.h"

#define MAX_IDLE_TIME 8
#define ACTIVITY_IDLE_ENERGY 1.0

class Objects;
class Activity;

class Idle : public Activity
{
private:
float mTimeInIdle;

public:
Idle() : mTimeInIdle(0)    { }
Idle(Objects *actor, Goods *target) : Activity(actor, target) { }

bool OnUpdate(float seconds);

};


The previous errors have been fixed after adding the pragma directive.

Thank the guys who helped.

Jack

Edited by lucky6969b, 01 June 2013 - 06:14 AM.

#20FLeBlanc  Members

3133
Like
1Likes
Like

Posted 01 June 2013 - 08:20 AM

If the line activity = new Idle(this, NULL); occurs inside Objects.h, as seems to be indicated by the info in the error message, then it's probably because where that line occurs there has only been a forward declaration of Idle. Go read what JTippetts posted again. If you want to use anything that is part of the class Idle (including constructors) then before you do so you have to include the full declaration of Idle. If the compiler encounters new Idle, and it still doesn't know what the fuck Idle looks like because all it has to work from is a forward declaration, then you're going to get that error. Whenever you have cyclical-dependency fuckery, you would probably be better off not putting any executable code at all inside your headers and keep it all to .cpp files.

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.