subclassing shared_ptr?

- I'm porting to C++ a huge java library. - Java constructor semantics is close to that of C++ but not identical. - boost::shared_ptr does nearly exactly what I want except for 1 little thing peculiar to the project I'm working on. The short story is that, for the C++ version, I need an "after ctor" method to be called before any other member function is allowed to be called. The logical next step was to override operator-> which led me to a long route ending now with boost::shared_ptr. I should be able to solve my problem by _patching_ my local copy of shared_ptr.hpp as follows: ... template<class Y> explicit shared_ptr(Y * p): px(p), pn(p, checked_deleter<Y>()) // Y must be complete { p->constructor() ; // single patch for my purpose detail::sp_enable_shared_from_this( pn, p, p ); } ... But obviously, I'd rather not do that. So I came up with: template <typename T> struct Bridge : public boost::shared_ptr<T> { template <typename Y> explicit Bridge(Y * y) : boost::shared_ptr<Y>(y) { if (y) { y->constructor() ; } } } ; But then, the guarantee given in the boost shared_ptr documenation was broken: Quote: shared_ptr<T> can be implicitly converted to shared_ptr<U> whenever T* can be implicitly converted to U*. In particular, shared_ptr<T> is implicitly convertible to shared_ptr<T const>, to shared_ptr<U> where U is an accessible base of T, and to shared_ptr<void>. So, I added a copy constructor: template <typename T> struct Bridge : public boost::shared_ptr<T> { template <typename Y> explicit Bridge(Y * y) : boost::shared_ptr<Y>(y) { if (y) { y->javaConstructor() ; } } template<typename Y> Bridge(Bridge<Y> const & r) : boost::shared_ptr<Y>(r) { } } ; But then I get: /Users/verec/Tools/boost_1_32_0/osx/main.cpp: In constructor `Bridge<T>::Bridge(const Bridge<Y>&) [with Y = DisplayStruct, T = DeviceStruct]': /Users/verec/Tools/boost_1_32_0/osx/main.cpp:243: instantiated from here /Users/verec/Tools/boost_1_32_0/osx/main.cpp:21: error: type 'class boost::shared_ptr<DisplayStruct>' is not a direct base of 'Bridge<DeviceStruct>' Here's the relevant part of the code: #include <iostream> #include <vector> #include <string> #include <sstream> #include <boost/shared_ptr.hpp> struct ObjectStruct { ObjectStruct() { } ; virtual void constructor() { } virtual ~ObjectStruct() { } } ; typedef Bridge<ObjectStruct> Object ; struct DeviceStruct : public ObjectStruct { typedef Bridge<DeviceStruct> Device ; DeviceStruct() { std::cout << "Device standard c++ constructor." << std::endl ; } virtual void deviceMethod() { std::cout << "DeviceStruct::deviceMethod." << std::endl ; } virtual void constructor() { std::cout << "java's Device::constructor." << std::endl ; } static Device current ; static Device getCurrent() { return current ; } } ; typedef Bridge<DeviceStruct> Device ; struct DisplayStruct : public DeviceStruct { typedef Bridge<DisplayStruct> Display ; DisplayStruct() { std::cout << "Display standard c++ constructor." << std::endl ; } DisplayStruct() { std::cout << "Display standard c++ constructor." << std::endl ; } virtual void constructor() { DeviceStruct::constructor () ; std::cout << "java's Display::constructor." << std::endl ; } virtual void deviceMethod() { DeviceStruct::deviceMethod () ; std::cout << "DisplayStruct::deviceMethod." << std::endl ; } virtual void displayMethod() { std::cout << "displayMethod." << std::endl ; } } ; typedef Bridge<DisplayStruct> Display ; void callDevice(Device d) { d->deviceMethod() ; } int main (int argc, char * const argv[]) { Display display(new Display) ; Device device(new DeviceStruct) ; callDevice(device) ; callDevice(display) ; return 0 ; } What am I missing ? Many Thanks. -- Jean-François Brouillet verec@mac.com

Jean-François Brouillet wrote:
So, I added a copy constructor:
template <typename T> struct Bridge : public boost::shared_ptr<T> {
template <typename Y> explicit Bridge(Y * y) : boost::shared_ptr<Y>(y) { if (y) { y->javaConstructor() ; } }
template<typename Y> Bridge(Bridge<Y> const & r) : boost::shared_ptr<Y>(r) { } } ;
But then I get:
/Users/verec/Tools/boost_1_32_0/osx/main.cpp:21: error: type 'class boost::shared_ptr<DisplayStruct>' is not a direct base of 'Bridge<DeviceStruct>'
That's because shared_ptr<Y> is not a base of Bridge<T>, shared_ptr<T> is. Change the templated copy constructor to: template<typename Y> Bridge(Bridge<Y> const & r) : boost::shared_ptr<T>(r) { } and it will compile. You can also use a static create function: class Display { public: typedef shared_ptr<Display> ref; static ref create() { ref r( new Display ); r->constructor(); return r; } private: Display() { ... } }; int main() { Display::ref d = Display::create(); }

On 2005-05-08 13:28:29 +0100, "Peter Dimov" <pdimov@mmltd.net> said:
template<typename Y> Bridge(Bridge<Y> const & r) : boost::shared_ptr<Y>(r) { }
That's because shared_ptr<Y> is not a base of Bridge<T>, shared_ptr<T> is . Change the templated copy constructor to:
template<typename Y> Bridge(Bridge<Y> const & r) : boost::shared_ptr<T>(r) { }
<red faced> I had to read "spot the changes" your definition three times before I noticed that you had changed my Y with a T. And *that* was it. One thousand thanks, Peter!. </red faced> -- Do your users a favor: give them Style: http://www.uiwithstyle.org
participants (2)
-
Jean-François Brouillet
-
Peter Dimov