I have a class that I made that I am using in thread above the class. Even though I did a prototype of the class at the top it still throws off those errors
error C2027: use of undefined type 'foo'
class foo;
DWORD WINAPI demo(LPVOID param)
{
foo a;
}
class foo
{
public:
int x;
};
Even though I did a prototype of the
class
With a forward declaration of the class you can create pointers and references to the class. This is because pointers/references are represented the same across all classes/structs/etc. They're all just addresses of memory. So, for example, you could create a second class that can accept or contains pointers or references before fully defining the class, ie:
class Bar
{
private:
foo* aFoo;
public:
Bar(foo* foo2) : aFoo(foo2) {}
};
However, until the compiler sees the full definition of the class, you can't instantiate it. Otherwise the compiler doesn't know how much memory to allocate and how to call the constructor and other methods. In most cases, C++ expects things to be defined before they are used. Forward declaration lets you get around this a little bit because pointers and references for any class are identical. So you can promise to the compiler you'll fully define it later.
Related
I am working with a GitHub library and ran across a derived class instantiation that perplexes me. In abbreviated form,
class A
{
public:
A() {}
int AFunc(void) { return(1); }
};
class B : public A
{
public:
B(void) : A() {}
int BFunc(void) { return(2); }
};
Within an include file, the class is instantiated as follows:
A &tObject = *(new B());
Sample code then refers to 'tObject' as global variable calling methods from class A and/or B.
For example:
tObject.AFunc();
tObject.BFunc();
So here's the question, is that instantiation legal?
The compiler is only fussing on the call to a service class's method, saying that class A has no such member. That error makes sense to me and I've narrowed the issue to the above explanation.
While I do not have broad compiler experience, I have been programming in C++ for many years. I've never seen such a construct.
Would someone kindly explain how an object declared, in my example, as 'class A' can access methods from the derived class B?
In my experience, I've always declared the derived class as a pointer and then accessed methods from the base or derived class using the '->' construct. Oftentimes, I've stored the derived class as a pointer to the base and then performed a cast to convert when or if I needed access to the derived class's methods.
An insight is highly appreciated.
It cannot. The compiler is right to complain, there is no way this is valid. Remember that C++ is a static language, which means that the compiler will try to find a function named BFunc in A, which it cannot, as there is no such function.
This might be a compiler extension of some sort, but anyways, this isn't legal standard C++. Most probably, the author wanted to make BFunc a virtual method in A, which would have made the access legal.
Would someone kindly explain how an object declared, in my example, as 'class A' can access methods from the derived class B?
As explained, this cannot be.
I've always declared the derived class as a pointer and then accessed methods from the base or derived class using the '->' construct.
You can also do this with references, not just with pointers. Although this is done less often than pointers, so this might explain why you haven't encountered this yet.
Oftentimes, I've stored the derived class as a pointer to the base and then performed a cast to convert when or if I needed access to the derived class's methods.
Exactly, this is the correct way to access the derived class members. As then the compiler will know the type of the object and can actually find BFunc and call it. Now, if the type is not really a B, then you have undefined behavior, but yes, this is what one should do.
Also, please get your terminology right:
the class is instantiated as follows
If there are no templates involved, then there is no instantiation happening. The only thing you are doing here is declaring or more specifically defining a variable named tObject.
// The declaration of the reference as a reference to the base class is not a problem, and is actually performed in some STL implementations.
class A
{
};
class B : public A
{
public:
void f1() {}
};
int main()
{
A * a = new B; // You know its OK using pointers
A & a2 = *(new B); // Also OK, a2 is a reference for a place in memory which is-a-kind-of A
// a2.f1(); // Will not compile - compiler only knows for sure its of type A
((B&) a2).f1(); // This will work. There is really a B there
return 0;
}
It is well-known that one cannot have a member of the type you're defining:
class Foo {
Foo member;
};
The reason is that this is an infinitely recursive, infinitely large object. However, we can have static members:
class Foo {
static Foo member;
};
We can do this because Foo is acting like a namespace; instances of Foo do not contain .member, so there's no infinite reference. Put another way, .member belongs to the class, not to the instance. What I would like to do is very similar:
class Foo {
class Bar {
Foo member;
};
};
Once again, Foo is acting like a namespace. Instances of Foo are actually empty. I would have to make a non-static field Bar Foo::bar; to start getting layout issues. Unfortunately, my compilers disagree (e.g. GCC):
<source>:3:14: error: field 'member' has incomplete type 'Foo'
Foo member;
^~~~~~
For what technical reason is this not allowed?
Long story short, it was easier to disallow this than to allow.
Here is an example that shows what could be difficult about it: C++ lets you combine nested class definition with a member declaration, like this:
class Foo {
class Bar {
Foo member;
} bar; // <<== Here
};
It is clear why this definition must be disallowed: unlike a class definition which could have been OK, member definition makes size computation impossible.
Of course the writers of the standard could have allowed class definitions to pass, at the expense of giving compiler writers additional work. However, it looks like they decided that allowing this feature is not worth the trouble, so they didn't make it an exception from the requirement of the class to be complete at the point of declaring an instance.
There is nothing wrong with what you what to do, and you can do so with different syntax.
Since the compiler wants to determine the size of class Bar, it needs to know the size of class Foo, But Foo's definition is not yet complete (The source code has not been entirely parsed by the compiler). The definition of Foo must be completed before using it in Bar.
Instead try forward declaring Bar inside Foo, then completing the definition of Bar after Foo, This way the size of Foo can be determined for use in Bar.
class Foo {
class Bar;
};
class Foo::Bar {
Foo member;
};
It's not allowed because you can't define a class with a member with an incomplete type, period. At the end of the class definition the class becomes complete and that is only possible if the sizes of all of its members are known.
For example, you get the same error, for the same reason, without nesting classes like this:
class Foo;
class Bar {
Foo member;
};
Sure, in your example the language could defer completing the definition of Foo::Bar until Foo is defined, but this would be inconsistent with how classes are defined generally. You'd have the weird behaviour of Foo::Bar being incomplete at a point in the source code after it was fully defined.
Am I missing something here?
class Foo;
class Bar {
public:
Foo foo;
};
class Foo { };
Error:
error C2079: 'Bar::foo' uses undefined class 'Foo'
When you forward-declare a class, you can make pointers and references to it, but you cannot make members of the type of forward-declared class: the full definition of Foo is needed to decide the layout of the outer class (i.e. Bar), otherwise the compiler cannot make a decision on the size and the structure of Bar.
This is allowed, though:
class Foo;
class Bar {
public:
Foo* fooPtr;
Foo& fooRef;
};
The reason the pointers and references to forward-declared classes are allowed is that the sizes of pointers and references do not depend on the structure of the class to which they point (or which they reference).
Yes you are missing something important: A question.
I assume you want to know what's wrong in the code, and why the compiler issues an error.
The compiler has to know the size of Foo in order to calculate the layout of the class Bar. The size of Foo objects is determined by their layout, to know that layout, the compiler has to know the class definition. At the point where you declare the Member variable foo, it merely knows that Foo exists, but not its size, because you have given it only a declaration, not a definition before.
I have a simple code below:
class B;
class A{
B b;
};
class B{
public:
B(){
}
};
In class A's definition, I have a B-typed property. Using MS Visual Studio to compile, I've got the following error:
error C2079: 'A::b' uses undefined class 'B'
Due to some reasons, I can't put class B's definition before class A's one. Any idea?
The compiler is already telling you what's wrong : A has a member data b which is of an undefined type. Your forward declaration:
class B;
is just that : a declaration, not a definition. Since class A contains an instance of B directly (not just a pointer to B), the compiler needs to know the exact size of B : it needs its definition, not just a declaration, i.e. a promise that B will exist at some point.
The simplest thing to do here would be to reorder things this way:
class B{
public:
B(){
}
};
class A{
B b;
};
Edit : see also this question for the difference between declaration and definition.
Further edit : an alternative would be to change your member data to a pointer or a reference.
Do note that this isn't a trivial syntax change: it has implications on the life-cycle of your objects since the object pointed by A::b may then survive the destruction of A.
If what you want is composition (B is a part of A and dies with A), using a pointer will make your life harder with little benefits.
More edits(!) : just realized I misread the end of your question; what are the reasons preventing you from declaring B before A ?
If they cannot be worked around, you may have to go the pointer route. These reasons might be a sign that your objects are too tightly coupled though ! (perhaps B needs to be an inner class of A ? Or simply be merged into a single object ?)
class A;
class B {
A * getA();
};
class A {
B b;
};
This is the typical way to solve this. You must have B's definition in order to have a B b; member.
You need a forward declaration in order to declare a reference/pointer to B, you need the full definition in order to do anything else with B (such as defining a variable, calling a member function and so on)
You can do what you wish if you change the reference to b into a pointer to B.
class A{
B* bPtr;
};
class B{
public:
B(){
}
};
In principle, you don't need an explicit declaration - that is, a forward declaration is all that is needed - when you don't need the actual size of the class, or access to the types and member functions inside the class.
In your original example, you are making a direct reference to B. As a result, the compiler needs to know everything about B, thus requiring an explicit declaration instead of a forward one.
By having your A class declaration using a pointer to B, then you can get away with a forward declaration.
edit
Some links might explain the concept for you:
http://www.goingware.com/tips/parameters/notrequired.html
http://www-subatech.in2p3.fr/~photons/subatech/soft/carnac/CPP-INC-1.shtml
http://www.codeguru.com/forum/showthread.php?t=358333 (see post #2)
http://en.wikipedia.org/wiki/Forward_declaration
C++ has the concept of an "incomplete" class and it is something you need to know.
Using an incomplete class allows you, in many situations, to use a class just knowing it is one, without knowing what is in it.
This enables the class detail to change later without requiring a recompile, thus it is a far weaker dependency in the coupling model.
You need a complete class to:
Have an instance of one.
Derive from it
Call any method on it.
delete a pointer to it.
You only need an incomplete class to:
Hold a pointer or reference to it.
Pass a pointer or reference to a function that takes a pointer or reference. (This can be a function that deletes the pointer, as long as it is fully defined at that point).
I think you only need an incomplete class to declare a function that returns one, and possibly to declare a function that takes one as a parameter, but at the time you define or call the function it needs to be complete, even if you don't use the return value.
I want to use forward declaration of a class in my software, so I can have typedefs
and use them inside the class full declaration.
Smth like this:
class myclass;
typedef boost::shared_ptr<myclass> pmyclass;
typedef std::list<pmyclass > myclasslist;
class myclass : public baseclass
{
private: // private member declarations
__fastcall myclass();
public: // public member declarations
__fastcall myclass(myclass *Parent)
: mEntry(new myclass2())
{
this->mParent = Parent;
}
const myclass *mParent;
myclasslist mChildren;
boost::scoped_ptr<myclass2> mEntry;
};
so my question is:
are there any drawbacks in this method? I recall some discussion on destructor issues with forward declaration but I did not get everything out of there.
or is there any other option to implement something like this?
Thanks.
EDIT:
I found the discussion I was referring to: here
The main drawback is everything. Forward declarations are a compromise to save compilation time and let you have cyclic dependencies between objects. However, the cost is you can only use the type as references and can't do anything with those references. That means, no inheritance, no passing it as a value, no using any nested type or typedef in that class, etc... Those are all big drawbacks.
The specific destruction problem you are talking about is if you only forward declare a type and happen to only delete it in the module, the behavior is undefined and no error will be thrown.
For instance:
class A;
struct C
{
F(A* a)
{
delete a; // OUCH!
}
}
Microsoft C++ 2008 won't call any destructor and throw the following warning:
warning C4150: deletion of pointer to incomplete type 'A'; no destructor called
: see declaration of 'A'
So you have to stay alert, which should not be a problem if you are treating warnings as errors.
From the C++ standard:
5.3.5/5:
"If the object being deleted has incomplete class type at the point of
deletion and the complete class has a non-trivial destructor or a
deallocation function, the behavior is undefined."