...
Consider a common application of a handle/body idiom that implements an abstract data type by a handle that contains a pointer to an implementation class.
Code Block | ||||
---|---|---|---|---|
| ||||
class Body; // incomplete class declaration class Handle { public: Handle(); ~Handle() { delete impl_; } // deletion of pointer to incomplete class // ... private: Body *impl_; }; |
...
The deletion of impl_
should be moved to a part of the code where Body
is defined.
Code Block | ||||
---|---|---|---|---|
| ||||
class Body { // ... }; Handle::~Handle() { delete impl_; } // correct. |
...
Alternatively, an appropriate smart pointer may be used in place of a raw pointer.
Code Block | ||||
---|---|---|---|---|
| ||||
class Handle { public: Handle(); ~Handle() {} // correct. // ... private: std::tr1::shared_ptr<Body> impl_; }; |
...
Similarly, while it is possible to cast a pointer or reference to an incomplete class, it is never a good idea to do so. Casting a class address often involves an adjustment of the address by a fixed amount that can only be determined after the layout and inheritance structure of the class is known, and this information is not available in the case of an incomplete class.
Code Block | ||||
---|---|---|---|---|
| ||||
class B { // ... }; B *getMeSomeSortOfB(); // ... class D; // incomplete declaration // ... B *bp = getMeSomeSortOfB(); D *dp = (D *)bp; // old-stlye cast: legal, but inadvisable dp = reinterpret_cast<D *>(bp); // new-style cast: legal, but inadvisable |
...