Проблема доступа к членам класса из вложенного
От: adr Украина  
Дата: 09.12.04 16:43
Оценка:
Необходимо унифицированное решение для вызова метода 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;

//----------------------------------------------------------
void TTraceSound::TAnonymousAdapter::Trace(eTraceMessageType, const char*, ...)
{
    TTraceSound::Play(); // Здесь error C2352
}
//----------------------------------------------------------



И какой же тогда смысл в объявлении классов как вложенных впринципе, если нет доступа к мемберам внешнего?
Re: Проблема доступа к членам класса из вложенного
От: Bell Россия  
Дата: 09.12.04 17:03
Оценка:
Здравствуйте, 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: Проблема доступа к членам класса из вложенного
От: Dr.Gigabit  
Дата: 09.12.04 20:39
Оценка:
Здравствуйте, adr, Вы писали:

adr> Технически анонимный адаптер это вложенный класс, для методов которого все члены внешнего оказываются в глобальной области видимости.


Может наследование попробовать?
... << RSDN@Home 1.1.4 @@subversion >>
Re: Проблема доступа к членам класса из вложенного
От: folk Россия  
Дата: 10.12.04 05:04
Оценка:
adr:

>
> namespace server_lib
> {
> class TTraceSound
> {
[]
> void Trace(eTraceMessageType, const char*, ...);
> 
> public:
> class TAnonymousAdapter
> {
> public:
> void Trace(eTraceMessageType, const char*, ...);
> };
[]
> };
> 
> }; // END OF NAMESPACE
>

>
> Так почему же его нельзы вызвать из метода Trace класса TAnonymousAdapter
> using namespace server_lib;
>
>
> //----------------------------------------------------------
> void TTraceSound::TAnonymousAdapter::Trace(eTraceMessageType, const char*, ...)
> {
> TTraceSound::Play(); // Здесь error C2352
> }
> //----------------------------------------------------------
>

>
> И какой же тогда смысл в объявлении классов как вложенных впринципе, если нет доступа к мемберам внешнего?

У вложенного класса в С++ есть доступ к членам внешнего, но нет неявного указателя на экземпляр внешнего. Можно добавить его явно:
class TTraceSound
{

  void Trace(eTraceMessageType, const char*, ...);

 public:
  class TAnonymousAdapter
  {
   public:
    void Trace(eTraceMessageType, const char*, ...) { outer_->Trace(...); }

   private:
    friend class TTraceSound;
    TAnonymousAdapter(TTraceSound* outer): outer_(outer) {}
    TTraceSound* outer_;
  };
};


PS Точка запятой здесь является ошибкой:
namespace server_lib {...};
Posted via RSDN NNTP Server 1.9 delta
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[2]: Проблема доступа к членам класса из вложенного
От: Hroftina Россия  
Дата: 10.12.04 08:03
Оценка:
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[3]: Проблема доступа к членам класса из вложенного
От: folk Россия  
Дата: 10.12.04 08:47
Оценка:
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) подразумевает создание класса, интерфейс которого удовлетворяет нашим требованиям, а реализуется посредством класса/классов с другим интерфейсом. Зачем вложенный класс?

мне самому непонятно, я просто показал что надо сделать чтобы избавиться от той ошибки
Posted via RSDN NNTP Server 1.9 delta
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[4]: Проблема доступа к членам класса из вложенного
От: Hroftina Россия  
Дата: 10.12.04 09:14
Оценка:
Действительно, "моя" дружба бессмысленна. Загнался... Вложенный класс — это что-то вроде члена класса, и доступ у него неограниченный. Тут дружба совсем не нужна вроде, получается.
Re[5]: Проблема доступа к членам класса из вложенного
От: folk Россия  
Дата: 10.12.04 09:37
Оценка:
Hroftina:

> Действительно, "моя" дружба бессмысленна. Загнался... Вложенный класс — это что-то вроде члена класса, и доступ у него неограниченный. Тут дружба совсем не нужна вроде, получается.


Дружбу я приплел сюда (наверное зря, лишнее усложнение) чтобы создавать экземпляры вложенного класса мог только внешний класс (забудем про copy ctor).
Posted via RSDN NNTP Server 1.9 delta
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[3]: Проблема доступа к членам класса из вложенного
От: adr Украина  
Дата: 10.12.04 12:17
Оценка:
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 Украина  
Дата: 10.12.04 12:27
Оценка:
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
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.