2013-07-03 2 views
0

я следующий класс третьей стороной (просто обертка вокруг какой-то указатель):Скрыть сведения о реализации через внутренний указатель

// 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 «s: отключить некоторые методы, добавить некоторые новые, скрывая его детали реализации. Я решил сделать следующее:

// 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, потому что он не соответствует моим потребностям и не хочет хранить его в моем собственном коде.

+0

Важно, если «A» имеет виртуальные функции-члены, в этом случае вы можете получить из A и создать свой собственный набор функций-членов и, если необходимо, вызвать некоторых из базового класса. – CyberGuy

+0

@CyberGuy Нет, 'A' не имеет виртуальных функций. Он не был предназначен для полиморфности. – user2547823

+0

Какую реализацию вы пытаетесь скрыть ?. Ваш 'pImpl' является фактически' public'. –

ответ

1

В комментарии вы говорите, что

Я не хочу выделять и удерживать 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(); 
} 

Это отвечает всем вашим другим требованиям:

  1. Вы не хотите, чтобы a.h был включен в new_a.h
  2. Вы хотите предоставить модифицированный интерфейс A, чтобы пользователи NewA ничего не знали о A и AImpl
  3. Вы хотите, чтобы скрыть реализацию A

Единственное, что не вполне отвечает на то, что в коде вы показываете конструктор по умолчанию A инициализирует pImpl элемент 0 - это странно! С каких пор пользователь класса PIMPL должен предоставить объект, который обернут классом PIMPL? Ср Википедия Opaque Pointer article.

+0

'A' объект фактически является узлом некоторого дерева, поэтому вокруг них будет создано множество таких объектов. Я не хочу выделять каждую из них на кучу, потому что это может повлиять на производительность. Все реальные вещи находятся в 'AImpl'. Я полагаю, что создание временного объекта в стеке для этой цели выполняется быстрее, чем динамически выделять его, но я могу ошибаться. – user2547823

+0

Я нашел [Fasti Pimpl Idiom] (http://www.gotw.ca/gotw/028.htm), который кажется лучшим решением, но в этом конкретном случае, поскольку 'A' предоставляет указатель на внутреннюю реализацию, я думаю, будет проще просто использовать его ... – user2547823

Смежные вопросы