Автоматическое преобразование A * в B * - PullRequest
1 голос
/ 26 апреля 2010

Предположим, мне дали класс A. Я хотел бы поместить указатели на него в небольшой класс B, своего рода интеллектуальный указатель, с ограничением на то, что B* автоматически преобразуется в A*, так что мне не нужно переписывать код, который уже использует A*.

Поэтому я бы хотел изменить B, чтобы следующие компиляции ...

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 *'
}

Обратите внимание, что B наследование от A не является вариантом (экземпляры A создаются на фабриках вне моего контроля) ...

Возможно ли это?

Спасибо.

Ответы [ 6 ]

3 голосов
/ 26 апреля 2010

тип pointer_to_b - указатель на B, который нельзя изменить; реализовано компилятором.

Вы можете сделать (* pointer_to_b) -> foo (), что будет делать правильно (если у вас есть переопределенный оператор -> ()). Однако это не позволит другому коду сделать правильные вещи, если вы передадите в него pointer_to_be.

Также позвольте мне добавить, что вы можете переопределить оператор & на B, чтобы вернуть A *, что может решить вашу проблему, в зависимости от конкретных случаев использования.

2 голосов
/ 26 апреля 2010

А как насчет функции get() как в boost::shared_ptr?

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

Тогда вы можете использовать его следующим образом:

pointer_to_b->get()->foo();      
doSomething(pointer_to_b->get());
0 голосов
/ 26 апреля 2010

Это должно работать с моей точки зрения

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);

}
0 голосов
/ 26 апреля 2010

B наследование от A - это опция , которая компилируется (по крайней мере, VS 2008):

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); 
}
0 голосов
/ 26 апреля 2010

Если я вспомню способ, которым shared_ptr обходит проблему, я думаю, у вас есть то, что вы никогда не пропускаете shared_ptr*, вы пропускаете shared_ptr объект. Таким образом, operator-> работает, потому что он вызывается для объекта, а не указатель на объект. Я рекомендую вам пройти около B<A> вместо B<A>*. Кому интересно, является ли класс-оболочка указателем или нет, если он представляет указатель на A, это не должно иметь значения.

0 голосов
/ 26 апреля 2010

Операторы, которых вы закомментировали в вашем struct B, выглядят так, как будто они должны заставить его делать то, что вы хотите ... почему они закомментированы?Разве это не работает, когда они не комментированы, и если нет, можете ли вы опубликовать ошибки?

...