views:

204

answers:

6

Hi,

Suppose I'm given a class A. I would like to wrap pointers to it into a small class B, some kind of smart pointer, with the constraint that a B* is automatically converted to an A* so that I don't need to rewrite the code that already uses A*.

I would therefore want to modify B so that the following compiles...

struct A {
  void foo() {}
};

template <class K>
struct B {
  B(K* k) : _k(k) {}
  //operator K*() {return _k;}
  //K* operator->() {return _k;}
private:
  K* _k;
};

void doSomething(A*) {}

void test() {
  A a;
  A* pointer_to_a (&a);
  B<A> b (pointer_to_a);
  //b->foo();             // I don't need those two...
  //doSomething(b);

  B<A>* pointer_to_b (&b);

  // Following represents existing code I don't want to change...
  pointer_to_b->foo();       // 'foo' : is not a member of 'B<K>'
  doSomething(pointer_to_b); // 'doSomething' : cannot convert parameter 1 from 'B<K> *' to 'A *'
}

Note that B inheriting from A is not an option (instances of A are created in factories out of my control)...

Is it possible?

Thanks.

+3  A: 

The type of pointer_to_b is pointer to B, which is a type you cannot modify; it's implemented by the compiler.

You can do (*pointer_to_b)->foo(), which will do the right thing (assuming you have the overridden operator->()). However, that won't let the other code do the right thing, if you pass pointer_to_be into it.

Also let me add that you can override operator& on B to return an A*, which might solve your problem, depending on the specific use cases.

Jon Watte
I wouldn't want to have to update all the existing code... :(
Xavier Nodet
Jon Watte
+2  A: 

What about function get() as in boost::shared_ptr?

template <class K>
struct B {
  B(K* k) : _k(k) {}
  K* get() { return _k;}
private:
  K* _k;
};

Then you could use it as follows:

pointer_to_b->get()->foo();      
doSomething(pointer_to_b->get());
Kirill V. Lyadvinsky
I would still need to change the existing code...
Xavier Nodet
Yes, but IMHO it will be clear.
Kirill V. Lyadvinsky
A: 

The operators you have commented out in your struct B look like they should make it do what you want... why are they commented out? Does it not work when they're uncommented, and if not, can you post the errors?

rmeador
Adding those operators allows the two conversions that I commented out because I don't need them. Uncommenting those operators does not change the errors that appear on the last two lines.
Xavier Nodet
A: 

If I recall the way shared_ptr gets around the issue I think you have is that you never pass around a shared_ptr*, you pass around a shared_ptr object. That way the operator-> works because it is being called on the object, not the pointer to the object. I recommend that you pass around B<A> instead of B<A>*. Who cares if the wrapper class is a pointer or not, as long as it represents a pointer to A it shouldn't matter.

messenger
A: 

B inheriting from A is an option, this compiles (VS 2008 at least):

struct A { 
  void foo() {} 
}; 

template <typename  T> 
struct B : T
{ 
  B(const T& t) : T(t) 
  {} 
}; 

void doSomething(A*) {} 

void test() { 
  A a; 
  B<A> b (a); 

  B<A>* pointer_to_b (&b); 

  // Following represents existing code I don't want to change... 
  pointer_to_b->foo();       
  doSomething(pointer_to_b); 
} 

cheers, AR

Alain Rist
A: 

This should work from my point of view

struct A {
  void foo() {}
};

template <class K>
struct B {
  B(K* k) : _k(k) {}
  operator K*() {return _k;}
  K* operator->() {return _k;}
private:
  K* _k;
};

void doSomething(A*) {}

void test() {
  A a;
  A* pointer_to_a (&a);
  B<A> pointer_to_b (pointer_to_a);

  // Following represents existing code NOT CHANGED
  pointer_to_b->foo();       
  doSomething(pointer_to_b);

}
Vicente Botet Escriba