Re[8]: Дружественные классы
От: Курилка Россия http://kirya.narod.ru/
Дата: 27.04.07 13:30
Оценка:
Здравствуйте, FDSC, Вы писали:

FDS>Т.е. вопрос, зачем вы разделяете класс I и класс C? Почему не перенести функциональность класса I в класс C?


+ сделать публичный интерфейс, а доступ к внутреннему классу I закрыть (а то так можно создать экземпляр итератора без коллекции, это обходится, но зачем добавлять костыли?).
Re[8]: Дружественные классы
От: alzt  
Дата: 27.04.07 14:03
Оценка:
Здравствуйте, FDSC, Вы писали:

FDS>Здравствуйте, alzt, Вы писали:


A>>В итоге о внутренней структуре знает только класс I, и немного его наследники.

A>>Остальные знают только об интерфейсе итератора.

FDS>А в чём преимущество этой архитектуры по сравнению с реализацией итератора прямо в C и его наследниках?

FDS>Т.е. вопрос, зачем вы разделяете класс I и класс C? Почему не перенести функциональность класса I в класс C?

Такая ситуация: один экземпляр класса C. Необходимо обеспечить его обход в двух потоках.
Если использовать один класс C, то придётся его копировать, что не всегда хорошо.
Re[9]: Дружественные классы
От: FDSC Россия consp11.github.io блог
Дата: 27.04.07 14:07
Оценка:
Здравствуйте, alzt, Вы писали:

A>Здравствуйте, FDSC, Вы писали:


FDS>>Здравствуйте, alzt, Вы писали:


A>>>В итоге о внутренней структуре знает только класс I, и немного его наследники.

A>>>Остальные знают только об интерфейсе итератора.

FDS>>А в чём преимущество этой архитектуры по сравнению с реализацией итератора прямо в C и его наследниках?

FDS>>Т.е. вопрос, зачем вы разделяете класс I и класс C? Почему не перенести функциональность класса I в класс C?

A>Такая ситуация: один экземпляр класса C. Необходимо обеспечить его обход в двух потоках.

A>Если использовать один класс C, то придётся его копировать, что не всегда хорошо.

С какой стати его придётся копировать?
Re[8]: Дружественные классы
От: igna Россия  
Дата: 27.04.07 14:09
Оценка:
Здравствуйте, alzt, Вы писали:

A>Забыл virtual подставить :


A>public:
A>    virtual void Reset()=0;
A>    virtual bool IsNext(){=0;
A>    virtual O Current()=0;


Спасибо, но и с этими изменениями не компилируется. Если можно дай компилируемый вариант.
Re[9]: Дружественные классы
От: alzt  
Дата: 27.04.07 14:19
Оценка:
Здравствуйте, igna, Вы писали:

I>Спасибо, но и с этими изменениями не компилируется. Если можно дай компилируемый вариант.


class O
{
};

class I;

class C
{
public:
    I GetIterator();
private:
    vector<O> m_elems;
    int Count();
    O GetElem(int index);

    friend class I;
};

class I
{
public:
    virtual void Reset()=0;
    virtual bool IsNext()=0;
    virtual O Current()=0;
protected:
    int Count(){return c->Count();}
    O GetElem(int index){return c->GetElem(index);}
private:
    C* c;
};

class I1 : I
{
public:
    I1():m_index(0){}
    void Reset(){m_index = 0;}
    bool IsNext(){return m_index<I::Count();}
    O Current(){return I::GetElem(m_index);}
private:
    int m_index;
};
Re[10]: Дружественные классы
От: alzt  
Дата: 27.04.07 14:21
Оценка:
Здравствуйте, FDSC, Вы писали:

A>>Такая ситуация: один экземпляр класса C. Необходимо обеспечить его обход в двух потоках.

A>>Если использовать один класс C, то придётся его копировать, что не всегда хорошо.

FDS>С какой стати его придётся копировать?


Объект класса C предположим имеет скрытую переменную m_index.
Тогда, если использовать один объект (ссылки, указатели на него), то разные потоки будут его изменять неопределённо.
Я не смогу гарантировать, что m_index при обходе не будет изменён где-то ещё.
Re[11]: Дружественные классы
От: FDSC Россия consp11.github.io блог
Дата: 27.04.07 14:23
Оценка:
Здравствуйте, alzt, Вы писали:

A>Здравствуйте, FDSC, Вы писали:


A>>>Такая ситуация: один экземпляр класса C. Необходимо обеспечить его обход в двух потоках.

A>>>Если использовать один класс C, то придётся его копировать, что не всегда хорошо.

FDS>>С какой стати его придётся копировать?


A>Объект класса C предположим имеет скрытую переменную m_index.

A>Тогда, если использовать один объект (ссылки, указатели на него), то разные потоки будут его изменять неопределённо.
A>Я не смогу гарантировать, что m_index при обходе не будет изменён где-то ещё.

Кто мешает прямо в классе создавать разные контексты поиска для разных потоков?
Re[8]: Дружественные классы
От: alzt  
Дата: 27.04.07 14:26
Оценка:
Здравствуйте, FDSC, Вы писали:

A>>В итоге о внутренней структуре знает только класс I, и немного его наследники.

A>>Остальные знают только об интерфейсе итератора.

FDS>А в чём преимущество этой архитектуры по сравнению с реализацией итератора прямо в C и его наследниках?

FDS>Т.е. вопрос, зачем вы разделяете класс I и класс C? Почему не перенести функциональность класса I в класс C?

А если мне потребуется ещё обход I2, скажем такой, чтобы объекты типа O перебирались по алфавиту, или только такие, которые имеют какое-то свойство, а остальные пропускались.
Тогда вся логика обхода будет сосредоточена в одном классе, а от класса C мне потребуется только вернуть нужный вид обхода.
Если же перенести функциональность класса I в класс C, то менять будет сложнее.
Re[9]: Дружественные классы
От: FDSC Россия consp11.github.io блог
Дата: 27.04.07 14:31
Оценка:
Здравствуйте, alzt, Вы писали:

A>Здравствуйте, FDSC, Вы писали:


A>>>В итоге о внутренней структуре знает только класс I, и немного его наследники.

A>>>Остальные знают только об интерфейсе итератора.

FDS>>А в чём преимущество этой архитектуры по сравнению с реализацией итератора прямо в C и его наследниках?

FDS>>Т.е. вопрос, зачем вы разделяете класс I и класс C? Почему не перенести функциональность класса I в класс C?

A>А если мне потребуется ещё обход I2, скажем такой, чтобы объекты типа O перебирались по алфавиту, или только такие, которые имеют какое-то свойство, а остальные пропускались.

A>Тогда вся логика обхода будет сосредоточена в одном классе, а от класса C мне потребуется только вернуть нужный вид обхода.
A>Если же перенести функциональность класса I в класс C, то менять будет сложнее.


Нет.
1. Можно сделать наследников класса C
или
2. Достаточно передать в сам класс C делегат (указатель на функцию) сравнения элементов, как это делается в стандартной реализации qsort
То же можно задать и для фильтра.

Т.е., вообще говоря, тип обхода и фильтра можно изменить независимо от самого кода обхода, например, даже другим классом, если очень хочется
Re[10]: Дружественные классы
От: alzt  
Дата: 27.04.07 14:38
Оценка:
Здравствуйте, FDSC, Вы писали:

A>>А если мне потребуется ещё обход I2, скажем такой, чтобы объекты типа O перебирались по алфавиту, или только такие, которые имеют какое-то свойство, а остальные пропускались.

A>>Тогда вся логика обхода будет сосредоточена в одном классе, а от класса C мне потребуется только вернуть нужный вид обхода.
A>>Если же перенести функциональность класса I в класс C, то менять будет сложнее.


FDS>Нет.

FDS>1. Можно сделать наследников класса C
Вариант плохой, т.к. при наличии других особенностей (не только тип обхода менять надо, а например и тип самого объекта) количество наследников резко увеличивается.
Пример: 2 обхода — прямой, реверсивный и 2 типа ОС — виндоус, юникс дают уже 4 наследника. 3 обхода, 3 типа ОС — 9.

FDS>или

FDS>2. Достаточно передать в сам класс C делегат (указатель на функцию) сравнения элементов, как это делается в стандартной реализации qsort
FDS>То же можно задать и для фильтра.

FDS>Т.е., вообще говоря, тип обхода и фильтра можно изменить независимо от самого кода обхода, например, даже другим классом, если очень хочется


Достаточно. Это решение намного проще и единственно верное?
Можно и шаблоны использовать, но количество деталей, которые надо будет держать в голове при этом не уменьшится.
Re[12]: Дружественные классы
От: alzt  
Дата: 27.04.07 14:40
Оценка:
Здравствуйте, FDSC, Вы писали:

A>>Объект класса C предположим имеет скрытую переменную m_index.

A>>Тогда, если использовать один объект (ссылки, указатели на него), то разные потоки будут его изменять неопределённо.
A>>Я не смогу гарантировать, что m_index при обходе не будет изменён где-то ещё.

FDS>Кто мешает прямо в классе создавать разные контексты поиска для разных потоков?


На мой взгяд это будет сложнее. Можно также простейший пример реализации?
Re[10]: Дружественные классы
От: igna Россия  
Дата: 27.04.07 14:42
Оценка:

"ComeauTest.c", line 14: error: function returning abstract class "I" is not
          allowed:
            function "I::Reset" is a pure virtual function
            function "I::IsNext" is a pure virtual function
            function "I::Current" is a pure virtual function
      I GetIterator();
       ^


http://www.comeaucomputing.com/tryitout/
Re[11]: Дружественные классы
От: alzt  
Дата: 27.04.07 14:48
Оценка:
Здравствуйте, igna, Вы писали:

I>

I>

I>"ComeauTest.c", line 14: error: function returning abstract class "I" is not
I>          allowed:
I>            function "I::Reset" is a pure virtual function
I>            function "I::IsNext" is a pure virtual function
I>            function "I::Current" is a pure virtual function
I>      I GetIterator();
I>       ^
I>


I>http://www.comeaucomputing.com/tryitout/


А Вы чем компилируете? и почему "ComeauTest.c"?
VS2005 отлично компилирует, не думаю что в других компиляторах без специальных опций проблемы будут.
Re[11]: Дружественные классы
От: FDSC Россия consp11.github.io блог
Дата: 27.04.07 14:56
Оценка:
Здравствуйте, alzt, Вы писали:

FDS>>или

FDS>>2. Достаточно передать в сам класс C делегат (указатель на функцию) сравнения элементов, как это делается в стандартной реализации qsort
FDS>>То же можно задать и для фильтра.

FDS>>Т.е., вообще говоря, тип обхода и фильтра можно изменить независимо от самого кода обхода, например, даже другим классом, если очень хочется


A>Достаточно. Это решение намного проще и единственно верное?

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

Это решение проще с той точки зрения, что вместо нового класса итератора и новой функции в C мы будем писать только вспомогательную функцию. Так что это решение чем-то проще — не нужно изменять класс C
По крайней мере, оно и не сложней, тем более, что над C можно сделать такие же как и у вас обёртки I, которые уже ничего не будут знать о приватном интерфейсе C

Я попробую написать пример кода, но позже
Re[12]: Дружественные классы
От: igna Россия  
Дата: 27.04.07 15:03
Оценка:
Здравствуйте, alzt, Вы писали:

A>VS2005 отлично компилирует


Да, но вроде не должен, поскольку GetIterator пытается вернуть объект абстрактного класса I. Давай заменим на I* GetIterator()?
Re[13]: Дружественные классы
От: igna Россия  
Дата: 27.04.07 15:24
Оценка:
Если заменить возвращаемое значение на указатель, то можно то же самое написать без использования friend, если определить I и I1 внутри C:

#include <vector>

using namespace std;

class O
{
};

class I;

class C
{
    class I
    {
    public:
        virtual void Reset()=0;
        virtual bool IsNext()=0;
        virtual O Current()=0;
    protected:
        int Count(){return c->Count();}
        O GetElem(int index){return c->GetElem(index);}
    private:
        C* c;
    };

    class I1 : I
    {
    public:
        I1():m_index(0){}
        void Reset(){m_index = 0;}
        bool IsNext(){return m_index<I::Count();}
        O Current(){return I::GetElem(m_index);}
    private:
        int m_index;
    };
public:
    I* GetIterator();
private:
    vector<O> m_elems;
    int Count();
    O GetElem(int index);
};
Re[13]: Пример реализации
От: FDSC Россия consp11.github.io блог
Дата: 27.04.07 16:13
Оценка:
Здравствуйте, alzt, Вы писали:

A>Здравствуйте, FDSC, Вы писали:


A>>>Объект класса C предположим имеет скрытую переменную m_index.

A>>>Тогда, если использовать один объект (ссылки, указатели на него), то разные потоки будут его изменять неопределённо.
A>>>Я не смогу гарантировать, что m_index при обходе не будет изменён где-то ещё.

FDS>>Кто мешает прямо в классе создавать разные контексты поиска для разных потоков?


A>На мой взгяд это будет сложнее. Можно также простейший пример реализации?


Это на C# 2.0:
using System;
using System.Collections.Generic;
using System.Text;

namespace FriendDown
{
    public class C<T>
    {
        public class SearchCtx
        {
            private SearchFilter _SF;
            private SequenceFunc _CF;
            private int          _Number;

            public SearchCtx(SearchFilter SF, SequenceFunc CF)
            {
                ResetCounter();

                _SF        = SF;
                _CF        = CF;
            }

            private SearchCtx()
            {
                throw new System.NotSupportedException();
            }

            public void ResetCounter()
            {
                _Number = 0;
            }

            public int Number
            {
                get
                {
                    return _Number;
                }
            }

            public int ToNext
            {
                get 
                {
                    return _Number++;
                }
            }

            public SequenceFunc CF
            {
                get
                {
                    return _CF;
                }
            }

            public SearchFilter SF
            {
                get
                {
                    return _SF;
                }
            }
        }

        private List<T> _ObjectList = new List<T>();

        public delegate bool SearchFilter(T sender);
        public delegate int  SequenceFunc(int Number, int Count, object O);

        public bool Next(SearchCtx SC, object SearchParams, out T t)
        {
            bool isFound = false;
            do
            {
                int i = SC.CF(SC.ToNext, _ObjectList.Count, SearchParams);

                if (i >= _ObjectList.Count || i < 0)
                {
                    t = default(T);
                    return false;
                }

                t = _ObjectList[i];

                isFound = SC.SF(t);
            }
            while (!isFound);

            return true;
        }

        public void Add(T addT)
        {
            _ObjectList.Add(addT);
        }

        private object LockObj = new Object();

        public SearchCtx GetSearch(SearchFilter SF, SequenceFunc CF)
        {
                return new SearchCtx(SF, CF);
        }                
    }

    static class Filter2
    {
        public static bool SF(int sender)
        {
            return (sender & 1) == 0 ? true : false;
        }

        public static int CF(int Number, int Count, object O)
        {
            return Number;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            C<int> c = new C<int>();

            bool isEndInput = false;
            do
            {
                int i;
                isEndInput = !Int32.TryParse(Console.ReadLine(), out i);
                if (!isEndInput)
                  c.Add(i);
            }
            while (!isEndInput);

            C<int>.SearchCtx ctx1 = c.GetSearch(delegate(int sender) {return true;},
                                                delegate(int Number, int Count, object O) { return Count - Number - 1; }
                                                );

            C<int>.SearchCtx ctx2 = c.GetSearch(Filter2.SF, Filter2.CF);

            int val1, val2;

            while (c.Next(ctx1, null, out val1))
            {
                while (c.Next(ctx2, null, out val2))
                {
                    Console.WriteLine("ctx2: " + val2.ToString());
                }

                ctx2.ResetCounter();

                Console.WriteLine("ctx1: " + val1.ToString());
            }

            Console.ReadLine();
        }
    }
}
Re[14]: Дружественные классы
От: alzt  
Дата: 28.04.07 07:45
Оценка:
Здравствуйте, igna, Вы писали:

I>Если заменить возвращаемое значение на указатель, то можно то же самое написать без использования friend, если определить I и I1 внутри C:


Можно и так, сразу не пришло в голову.
Только тогда обернуть лучше указатель.
Re[13]: Дружественные классы
От: alzt  
Дата: 28.04.07 07:50
Оценка:
Здравствуйте, igna, Вы писали:

I>Здравствуйте, alzt, Вы писали:


A>>VS2005 отлично компилирует


I>Да, но вроде не должен, поскольку GetIterator пытается вернуть объект абстрактного класса I. Давай заменим на I* GetIterator()?


Понял почему он компилируется: GetIterator() я не определяю, а насчёт класса I — в момент определения класса C о нём ничего не известно (что он абстрактный). Надо указатель возвращать.

Проверить пока не могу — а в C# подобный пример скомпилируется?
Re[14]: Пример реализации
От: alzt  
Дата: 28.04.07 07:54
Оценка:
Здравствуйте, FDSC, Вы писали:

FDS>Здравствуйте, alzt, Вы писали:


Выглядит не проще, не думаю, что в логике моего примера (корявого, как выяснилось выше — торопился) разобраться будет сложнее.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.