Reputation: 4278
I have a class that derives from a C struct. The class does not do anything special, other than initialization in the constructor, deinitialization function during the destructor, and a few other methods that call into C functions. Basically, it's a run-of-the-mill wrapper. Using GCC, it complained that my destructor was not virtual, so I made it that. Now I run into segfaults.
/* C header file */
struct A
{
/* ... */
}
// My C++ code
class B : public A
{
public:
B() { /* ... init ... */ }
virtual ~B() { /* ... deinit ... */ }
void do()
{
someCFunction(static_cast<A *>(this));
}
};
I was always under the assumption that the static_cast
would return the correct pointer to the base class, pruning off the virtual table pointer. So this may not be the case, since I get a segfault in the C function.
By removing the virtual
keyword, the code works fine, except that I get a gcc warning. What is the best work around for this? Feel free to enlighten me :).
Upvotes: 2
Views: 245
Reputation: 146910
Both the explicit and implicit conversion to A*
are safe. There is neither need for an explicit cast, nor is it going to introduce vtables anywhere, or anything like that. The language would be fundamentally unusable if this were not the case.
I was always under the assumption that the static_cast would return the correct pointer to the base class, pruning off the virtual table pointer.
Is absolutely correct.
The destructor need be virtual
only if delete ptr;
is called where ptr
has type A*
- or the destructor invoked manually. And it would be A
's destructor that would have to be virtual, which it isn't.
Whatever the problem is in your code, it has nothing to do with the code shown. You need to expand your sample considerably.
Upvotes: 4
Reputation: 12204
That's not how static_cast
works. A pointer to an object continues to be the same pointer, just with a different type. In this case, you're converting a pointer to a derived type (B
) into a pointer to the base type (A
).
My guess is that casting the pointer does not actually change the pointer value, i.e., it's still pointing to the same memory address, even though it's been cast into an A*
pointer type. Remember that struct
and class
are synonyms in C++.
As @Luchian stated, if you're mixing C and C++, it's better to keep the plain old C structs (and their pointers) as plain old C structs, and use type composition instead of inheritance. Otherwise you're mixing different pointer implementations under the covers. There is no guarantee that the internal arrangement of the C struct and the C++ class are the same.
UPDATE
You should surround the C struct declaration with an extern "C"
specification, so that the C++ compiler knows that the struct is a pure C struct:
extern "C"
{
struct A
{
...
};
}
Or:
extern "C"
{
#include "c_header.h"
}
Upvotes: 1
Reputation: 258598
The destructor of base classes should be virtual. Otherwise, there's a chance that you run into undefined behavior. This is just a speculation, as the code is not enough to tell the actual reason.
Try making the destructor of A
virtual and see if it crashes.
Note that a class
and a struct
are the same thing, other than default access level, so the fact that one's a class and the other a struct has nothing to do with it.
EDIT: If A
is a C-struct, use composition instead of inheritance - i.e. have an A
member inside of B
instead of extending it. There's no point of deriving, since polymorphism is out of the question.
Upvotes: 1