У меня есть следующий сторонний класс (просто обертка вокруг некоторого указателя):
// a.h
class AImpl;
class A
{
AImpl* pImpl;
public:
A(): pImpl(0) {}
A(AImpl* ptr): pImpl(ptr) {}
...
AImpl* getImpl() const { return pImpl; }
...
void someMethodOfA();
};
Я хочу изменить A
Интерфейс: отключите некоторые методы, добавьте несколько новых, скрывая при этом детали реализации. Я решил сделать следующее:
// new_a.h
class AImpl;
class A;
class NewA
{
AImpl* pImpl;
public:
NewA( const A& a );
...
void newMethodOfA();
...
};
//new_a.cpp
#include "a.h"NewA::NewA( const A& a ): pImpl( a.getImpl() ) {}
...
void NewA::newMethodOfA()
{
A( pImpl ).someMethodOfA();
}
...
Это нормально? Может быть, есть лучшее решение? я хочу измениться A
интерфейс, потому что он не соответствует моим потребностям и не хочу хранить его в своем собственном коде.
В комментарии вы говорите, что
Я не хочу выделять A и удерживать A * pImpl, потому что это уже обертка вокруг некоторого указателя (AImpl)
Несмотря на это требование, вы выделяете временный A
объект в NewA::newMethodOfA()
, Каким образом это должно быть лучше, чем распределение A
один раз и просто использовать повторно? Ваше решение не является хорошим, потому что 1) вы создаете новый временный A
снова и снова, и 2) вы заставляете пользователей NewA
предоставить экземпляр A
вместо того, чтобы просто создать его самостоятельно.
Я предлагаю вам прикусить пулю и просто сделать правильную реализацию «PIMPL поверх PIMPL» (как выразился капитан Obvlious):
// new_a.h
class A;
class NewA
{
A* pImpl;
public:
NewA();
~NewA();
void newMethodOfA();
};
//new_a.cpp
#include "a.h"NewA::NewA() : pImpl( new A() ) {}
NewA::~NewA() { delete pImpl; }
void NewA::newMethodOfA()
{
pImpl->someMethodOfA();
}
Это соответствует всем вашим другим требованиям:
a.h
включен в new_a.h
A
так что пользователи NewA
не буду ничего знать о A
а также AImpl
A
Единственное, что не совсем соответствует, — это то, что в коде вы показываете конструктор по умолчанию A
инициализирует его pImpl
член 0 — это странно! С каких это пор пользователь класса PIMPL должен предоставлять объект, который обернут классом PIMPL? Ср Википедия Непрозрачная статья указателя.
Других решений пока нет …