Необходимо унифицированное решение для вызова метода Trace для экземпляра произвольного класса.
Для решения такого класса задач разработан патерн "Анонимный адаптер". Эта концепция отлично работает в Java, Технически анонимный адаптер это вложенный класс, для методов которого все члены внешнего оказываются в глобальной области видимости. Попробовал реализовать конструкцию на С++ и получил ошибку
c:\mine\ServerLib\traceSound.cpp(67): error C2352: 'server_lib::TTraceSound::Play' : illegal call of non-static member function
Компилятор Microsoft VC7
Как видно из объявления, метод Play() класса TTraceSound объявлен в области видимости TAnonymousAdapter.
namespace server_lib
{
class TTraceSound
{
private:
//public:
std::string m_szFileName;
unsigned int m_DeviceID;
bool m_fDeviceOpened;
const int m_Freq;
const int m_Time;
private:
void CloseDevice();
public:
bool Link(const char* szFileName);
void Unlink();
unsigned long Play();
void Trace(eTraceMessageType, const char*, ...);
public:
class TAnonymousAdapter
{
public:
void Trace(eTraceMessageType, const char*, ...);
};
public:
TTraceSound();
virtual ~TTraceSound();
};
}; // END OF NAMESPACE
Так почему же его нельзы вызвать из метода Trace класса TAnonymousAdapter
using namespace server_lib;
Здравствуйте, adr, Вы писали:
adr>Необходимо унифицированное решение для вызова метода Trace для экземпляра произвольного класса. adr>Для решения такого класса задач разработан патерн "Анонимный адаптер". Эта концепция отлично работает в Java, Технически анонимный адаптер это вложенный класс, для методов которого все члены внешнего оказываются в глобальной области видимости. Попробовал реализовать конструкцию на С++ и получил ошибку
adr>c:\mine\ServerLib\traceSound.cpp(67): error C2352: 'server_lib::TTraceSound::Play' : illegal call of non-static member function
adr>Компилятор Microsoft VC7
В С++ вложенный класс не имеет доступа к членам объемлющего класса.
adr>И какой же тогда смысл в объявлении классов как вложенных впринципе, если нет доступа к мемберам внешнего?
Ну, применение вложенных классов совсем не ограничивается доступом к членам объемлющего.
Воспользуйся поиском (когда он заработает) — этот вопрос обсуждался несколько раз.
Любите книгу — источник знаний (с) М.Горький
Re: Проблема доступа к членам класса из вложенного
Здравствуйте, adr, Вы писали:
adr> Технически анонимный адаптер это вложенный класс, для методов которого все члены внешнего оказываются в глобальной области видимости.
Может наследование попробовать?
... << RSDN@Home 1.1.4 @@subversion >>
Re: Проблема доступа к членам класса из вложенного
Только вот дружба должна быть в другую сторону...
class TTraceSound {
friend class TAnonymousAdapter;
...
А зачем это все нужно?
Петтерн адаптер (wrapper) подразумевает создание класса, интерфейс которого удовлетворяет нашим требованиям, а реализуется посредством класса/классов с другим интерфейсом. Зачем вложенный класс?
Re[3]: Проблема доступа к членам класса из вложенного
Hroftina:
> F>class TTraceSound > F>{ > > F> void Trace(eTraceMessageType, const char*, ...); > > F> public: > F> class TAnonymousAdapter > F> { > F> public: > F> void Trace(eTraceMessageType, const char*, ...) { outer_->Trace(...); } > > F> private: > F> friend class TTraceSound; > F> TAnonymousAdapter(TTraceSound* outer): outer_(outer) {} > F> TTraceSound* outer_; > F> }; > F>}; > F>[/c] > > Только вот дружба должна быть в другую сторону... > class TTraceSound { > friend class TAnonymousAdapter;
В "твою" сторону дружба точно бессмысленна (по крайней на современных компиляторах).
Класс-член внешнего класса имеет доступ к приватным членам внешнего, точно также как функция-член класса имеет доступ к приватным членам класса.
> ... > > А зачем это все нужно? > Петтерн адаптер (wrapper) подразумевает создание класса, интерфейс которого удовлетворяет нашим требованиям, а реализуется посредством класса/классов с другим интерфейсом. Зачем вложенный класс?
мне самому непонятно, я просто показал что надо сделать чтобы избавиться от той ошибки
Действительно, "моя" дружба бессмысленна. Загнался... Вложенный класс — это что-то вроде члена класса, и доступ у него неограниченный. Тут дружба совсем не нужна вроде, получается.
Re[5]: Проблема доступа к членам класса из вложенного
Hroftina:
> Действительно, "моя" дружба бессмысленна. Загнался... Вложенный класс — это что-то вроде члена класса, и доступ у него неограниченный. Тут дружба совсем не нужна вроде, получается.
Дружбу я приплел сюда (наверное зря, лишнее усложнение) чтобы создавать экземпляры вложенного класса мог только внешний класс (забудем про copy ctor).
H>А зачем это все нужно? H>Петтерн адаптер (wrapper) подразумевает создание класса, интерфейс которого удовлетворяет нашим требованиям, а реализуется посредством класса/классов с другим интерфейсом. Зачем вложенный класс?
возникла идея написать "нормальный" Trace для вывода отладочной инфы.
Начиналось всё с консольки на которую выбрасывались строки, далее потребовалось писать логи в файл, потом сигнализировать звуком об ошибках, а иногда всё это вместе или в любых комбинациях.
Для этого всего родился TTraceBuffer задачей которого является раскидывать передаваемые ему сообщения на все прилинкованые объекты трассировки (Экземпляры классов TTraceConsole, TTraceSound, TTraceFile или другой TTraceBuffer) или ставить в очередь, если ни один из экз. указаных классов не прилинкован.
пример:
/**
* Необходимо отладить функцию foo()
*/
TTraceBuffer buff;
TTraceConsole con;
TTraceFile file;
...
file.Link("c:\\logfile.txt"); // указываем в какой фаул выводить логи
con.SetTitle("XXX"); // можем указать заголовок окна консоли, если её цель недебаг, а вывод инфы в релизе
/**
* связываем буфер с объектами вывода.
* объекты устанавл в кольцевой стек в виде структур содерж указатель на экз и константу,
* определяющую тип объекта вывода
*/
buff.Link(&con, TRACE_CONSOLE_OBJ);
...
void TClass::foo(int iParam, char* const szCommand)
{
int res = int();
buff.Link(&file, TRACE_FILE_OBJ); // именно этот результат нужно ещё и в файл сохранить
....
/**
* Выводим сообщение
* При этом buff пробегает по всем прилинкованым объектам вывода,
* в данн случае file и con, вызывая соответственно file.Trace и con.Trace
*
* ДЫК ВОТ
* Я хотел иметь единое решение вызова ::Trace для произвольного типа объекта вывода
* при условии поддержки им метода.
* Напрашивается шаблон, но из-за динамического подключения разнотипных объектов не катит.
*/
buff.Trace(TRACE_MSG_INFO, "Результат работы %d, вход параметры: %d, %s", res, iParam, szCommand);
buff.Unlink(&file); // больше в файл не выводим (Только на консоль)
...
}
/**
* На данный момент я использую такую конструкцию:
* при выводе я достаю из кольцевого стека структуру (указ на объект; идентификатор типа),
* привожу объект к типу в соотв с указаным при линковке и вызываю Trace
*
* Так вот, очень хотелось вместо структуры хранить только экз анонимных адаптеров
* выполняющих вызов методов тех классов, в кот они инкапсулированы.
* Виртуальность не катит т.к. нужно вызвать снизу вверх а не наоборот
*/void TTraceBuffer::CastAndTrace(const TAnonymousTracer& tracer,
const TTracePriorityMessage& item )
{
switch (tracer.m_TracerObjectType)
{
case TRACE_OBJ_BUFFER:
{
( static_cast<TTraceBuffer*>( tracer.m_hTracer ) )->Trace(item.m_Type, item.m_String.c_str());
break;
}
case TRACE_OBJ_CONSOLE:
{
( static_cast<TTraceConsole*>( tracer.m_hTracer ) )->Trace(item.m_Type, item.m_String.c_str());
break;
}
case TRACE_OBJ_FILE:
{
( static_cast<TTraceFile*>( tracer.m_hTracer ) )->Trace(item.m_Type, item.m_String.c_str());
break;
}
case TRACE_OBJ_SOUND:
{
( static_cast<TTraceSound*>( tracer.m_hTracer ) )->Trace(item.m_Type, item.m_String.c_str());
break;
}
} // END SWITCH( tracer.m_TracerObjectType )
}
Re[4]: Проблема доступа к членам класса из вложенного
adr>buff.Link(&con, TRACE_CONSOLE_OBJ); adr>...
adr>void TClass::foo(int iParam, char* const szCommand) adr>{ adr> int res = int(); adr> buff.Link(&file, TRACE_FILE_OBJ); // именно этот результат нужно ещё и в файл сохранить
Тут просто опечатка
TRACE_FILE_OBJ = TRACE_OBJ_FILE, а TRACE_CONSOLE_OBJ = TRACE_OBJ_CONSOLE