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."
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;
}
Is it possible to separate class declaration from its definition? Of course it is, but what if I want to have an object of this class before the actual definition of it? Consider the following example:
class ID3_Reader{
public:
// code omitted for brevity
protected:
class Mp3_File;
Mp3_File mFile;
};
It's obvious that it will not compile. I would have to define the Mp3_File class inside the ID3_Reader class. It's not a problem when I have just two classes. What if there would be like five of them? My code would become pretty messy. To avoid this problem I would have to separate the class declarations from their definitions. How can I achieve that? Remember that I need an instance of the Mp3_File class inside the ID3_Reader class.
The reason why I'm using nested classes is because I don't want some other programmer to use the Mp3_File class. I used "protected" keyword because I will create classes based on the ID3_Reader class.
You can achive this by using a pointer like the other guys answered:
class Mp3_File; // forward declaration of class Mp3_File
class ID3_Reader{
public:
// code omitted for brevity
protected:
Mp3_File *mFile;
};
Or you can declare the constructor of class Mp3_File private and declare class ID3_Reader friend of class Mp3_File:
class Mp3_File {
Mp3_File() {} // constructor is private
friend class ID3_Reader;
};
class ID3_Reader{
public:
// code omitted for brevity
protected:
Mp3_File mFile;
};
auto main() -> int {
ID3_Reader r;
Mp3_File m; // Error Mp3_File constructor is private!
return 0;
}
Thus, other people won't be able to use Mp3_File while you can use it in the scope of class ID3_Reader.
It won't compile because the compiler doesn't know how much memory that Mp3_File class will use. If you change it to a pointer
class ID3_Reader{
public:
// code omitted for brevity
protected:
class Mp3_File;
Mp3_File *mFile;
};
that compiles just fine (a pointer has a fixed size - http://ideone.com/VmmXfK).
I suggest using a pointer instead of a complete member variable and initialize/deinitialize it in the ctor/dtor.
I don't see another way of doing it without changing the "nested classes" design.
You can achieve that by using pointers. Recall that although you must have a full class to define a variable, a simple forward declaration is good to define a pointer:
class ID3_Reader{
public:
// code omitted for brevity
protected:
class Mp3_File;
Mp3_File *mFile;
};
Unfortunately, this puts you on the hook for managing the memory for the nested class, but it does hide all of the internals of the class from outside programmers.
Instead of defining mFile as an instance of Mp3_File, define it as a pointer to an Mp3_File. That way you won't need to know the definition in the header file. Or better yet - use a smart pointer. You will then need to create the real instance by using new in the class constructor and delete it in ID3_Reader's destructor.
If you wish to stay with your current syntax to access mFile from outside of the class, dereference it inside the accessor function:
Mp3_File& getMp3(){ return *mFile; };
Then - if Mp3_File has an overloaded operator() (or any other overloaded operator as a matter of fact), you won't need to dereference it every time manually.
You can make your class a class template to work around this restriction: for class templates the definition of the nested type needs to be visible at instantiation time, not while looking at the definition of the class template. You might want to use a typedef to actually name the used instantiation to avoid the need to have a trailing <>. Here is a quick demo:
template <typename = void>
class ID3_ReaderT {
public:
// code omitted for brevity
protected:
class Mp3_File;
Mp3_File mFile;
};
typedef ID3_Reader<> ID3_Reader;
template <typename T>
class ID3_ReaderT<T>::Mp3_File {
};
int main()
{
ID3_Reader reader;
}
Of course, it still means that every user of ID3_Reader needs to see the definition of the nested type. If you want to avoid that, your option is on level indirection, i.e., using a pointer as was already stated by multiple answers.
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.
Okay, so I have been working on a homework project and found a way that will let me finish the homework and get it turned in, but it is still bothering me.
I have a base class that is dynamically allocating some other classes, and a Derived class.
//header
class Base
{
Private:
Type *type_ptr;
Public:
Base();
Base(Type &new_type);
//getters and setters
}
class Derived : public Base
{
Private:
Type2 *type2_ptr;
Public:
Derived();
Derived(Type, Type2) : Base(Type);
}
What I want to figure out is what this should look like in my .cpp file, instead of doing it in-line like so,
Derived(Type new_type, Type2 new_type2): Base(new_type){
type2_ptr = new Type2(new_type2);
};
edit: if I try something like the above in my .cpp that I get errors like this, always two of them too...
undefined reference to `vtable for Derived'
undefined reference to `vtable for Derived'
header:
/* Base same as yours */
class Derived : public Base
{
Private:
Type2 *type2_ptr;
Public:
Derived();
Derived(Type&, Type2);
}
cpp:
Base::Base(): type_ptr(NULL)
{
// implementation goes here
}
Base::Base(Type &new_type): type_ptr(&new_type)
{
// implementation goes here
}
Derived::Derived()
{
// implementation goes here
}
Derived::Derived(Type& new_type, Type2 new_type2): Base(new_type),
type2_ptr(new Type2(new_type2))
{
// implementation goes here
}
note thet new_type is reference, not local variable in Derived, so variable passed to Derived must be in proper scope!
Outside of class you need to use Derived:: for all constructors and functions!
Derived::Derived(Type new_type, Type2 new_type2): Base(new_type)
{//^^^^^^^^^ note this
type2_ptr = new Type2(new_type2);
};
Also consider using initialization-list as much as possbible. Here is one example!
Derived::Derived(Type new_type, Type2 new_type2): Base(new_type), type2_ptr(new Type2(new_type2))
//^^^^ note this!
{
};
You've not shown everything. In the code you've shown, there
should be no vtable, since there are no virtual functions (and
the class isn't polymorphic, regardless of the inheritance.
Supposing that there are virtual functions, you should almost
certainly add a virtual destructor to Base.
Beyond that, the definition in the .cpp file should be:
Derived::Derived(Type new_type, Type2 new_type2)
: Base(new_type)
, type2_ptr(new Type2(new_type2))
{
}
Add the Derived:: in front of your definition, and there's
nothing in the code you expose which should cause problems. You
really should provide a complete example of the code which does
cause the problem; otherwise, we can just guess.
I have 2 classes: DataObject and DataElement. DataObject holds pointers to (only) DataElements, and a DataElement contains pointers to several types, among which a DataObject.
This used to be no problem, since I only use pointers to DataObjects in DataElement, so a forward declaration of DataObject in the header of DataElement is enough.
Now, however, I try to add a destructor to DataElement, in which I need a delete on a DataObject. On this the compiler says:
dataelement/destructor.cc: In destructor ‘DataElement::~DataElement()’:
dataelement/destructor.cc:8: warning: possible problem detected in invocation of delete operator:
dataelement/destructor.cc:8: warning: invalid use of incomplete type ‘struct DataObject’
dataelement/dataelement.h:7: warning: forward declaration of ‘struct DataObject’
dataelement/destructor.cc:8: note: neither the destructor nor the class-specific operator delete will be called, even if they are declared when the class is defined.
How can I solve this? A forward declaration is apparently not enough, while I cannot include the complete header for DataObject, since that gives me a circular dependency again.
Thanks in advance!
Define the destructor in a .cpp file that includes both headers.
Make the destructor for the first class defined outside of the class body and after the second class, e.g.
class DataElement;
class DataObject
{
DataElement* elem;
public:
~DataObject();
};
class DataElement
{
DataObject* obj;
public:
~DataElement() { delete obj; }
};
DataObject::~DataObject()
{
delete elem;
}