Кто сказал что в С++ нет виртуальных конструкторов?
От: WolfHound  
Дата: 04.06.03 17:05
Оценка: 37 (4) -1
В С++ нет так называемых виртуальных конструкторов что дельфисты расценивают как большой не достаток. Но сложно ли их реализовить? НЕТ!
Пример
Unit1.h
#pragma once
#include "meta.h"
struct Base
{
    virtual void Hello()=0;
    Base()
    {
        std::cout<<"Base ctor"<<std::endl;
    }
    virtual ~Base()
    {
        std::cout<<"Base dtor"<<std::endl;
    }
};
void DoSome(Meta<Base> meta);

Unit1.cpp
#include "stdafx.h"
#include "Unit1.h"
void DoSome(Meta<Base> meta)
{
    scoped_meta_ptr<Base> ptr1(meta);//Создает обьект класса переданого в качестве параметра.
                    //реализована концепция не разделимого владения
    shared_meta_ptr<Base> ptr2(meta);//Тоже создает обьект но реализован подсчет ссылок.
}

Unit2.cpp
#include "stdafx.h"
#include "Unit1.h"
struct Derived:Base
{
    void Hello()
    {
        std::cout<<"Derived Hello"<<std::endl;
    }
    Derived()
    {
        std::cout<<"Derived ctor"<<std::endl;
    }
    ~Derived()
    {
        std::cout<<"Derived dtor"<<std::endl;
    }
};
int _tmain(int argc, _TCHAR* argv[])
{
    DoSome(Meta<Derived>());
    return 0;
}

Не проверял но по идее должно работать и через границу длл.


А это сам код. Нуждается в доработке но это вполне рабочий прототип.
#pragma once
template<class T>
struct scoped_meta_ptr;
template<class T>
struct shared_meta_ptr;
template<class T>
struct Meta
{
    friend struct scoped_meta_ptr;
    friend struct shared_meta_ptr;
    Meta(){}
    template<class U>
    Meta(const Meta<U>&)
    {
        creator=&Create<U>;
        destroyer=&Destroy;
    }
private:
    typedef T*(*Creator)();
    Creator creator;
    typedef void(*Destroyer)(T*);
    Destroyer destroyer;

    template<class U>
    static T* Create()
    {
        return new U;
    }
    static void Destroy(T* ptr)
    {
        delete ptr;
    }
};
template<class T>
struct scoped_meta_ptr
{
    friend struct shared_meta_ptr;
    explicit scoped_meta_ptr(Meta<T> meta)
        :meta_(meta)
        ,ptr_(meta_.creator())
    {
    }
    scoped_meta_ptr(scoped_meta_ptr& that)
        :meta_(that.meta_)
        ,ptr_(that.ptr_)
    {
        that.ptr_=0;
    }
    scoped_meta_ptr& operator=(scoped_meta_ptr& that)
    {
        if(this==&that)return *this;
        meta_.destroyer(ptr_);
        meta_=that.meta_;
        ptr_=that.ptr_;
        that.ptr_=0;
        return *this;
    }
    ~scoped_meta_ptr()
    {
        meta_.destroyer(ptr_);
    }
    T* operator ->()
    {
        return ptr_;
    }
    operator bool() const
    {
        return ptr_?true:false;
    }
private:
    Meta<T> meta_;
    T* ptr_;
};
template<class T>
struct shared_meta_ptr
{
    explicit shared_meta_ptr(Meta<T> meta)
        :meta_(meta)
        ,ptr_(meta_.creator())
        ,count_(new int(1))
    {
    }
    shared_meta_ptr(const shared_meta_ptr& that)
        :meta_(that.meta_)
        ,ptr_(that.ptr_)
        ,count_(that.count_)
    {
        ++(*count_);
    }
    shared_meta_ptr& operator=(const shared_meta_ptr& that)
    {
        if(this==&that)return *this;
        Free();
        meta_=that.meta_;
        ptr_=that.ptr_;
        count_=that.count_;
        ++(*count_);
        return *this;
    }
    shared_meta_ptr(scoped_meta_ptr<T>& that)
        :meta_(that.meta_)
        ,ptr_(that.ptr_)
        ,count_(new int(1))
    {
        that.ptr_=0;
    }
    shared_meta_ptr& operator=(scoped_meta_ptr<T>& that)
    {
        Free();
        meta_=that.meta_;
        ptr_=that.ptr_;
        count_=new int(1);
        that.ptr_=0;
        return *this;
    }
    ~shared_meta_ptr()
    {
        Free();
    }
    T* operator ->()
    {
        return ptr_;
    }
    operator bool() const
    {
        return ptr_?true:false;
    }
    bool operator==(const shared_meta_ptr& that)
    {
        return ptr_==that.ptr_;
    }
    bool operator!=(const shared_meta_ptr& that)
    {
        return ptr_!=that.ptr_;
    }
private:
    void Free()
    {
        if(!--(*count_))
        {
            delete count_;
            meta_.destroyer(ptr_);
        }
    }
    Meta<T> meta_;
    T* ptr_;
    int* count_;
};
... << RSDN@Home 1.0 beta 6a >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re: Кто сказал что в С++ нет виртуальных конструкторов?
От: ZORK Россия www.zorkaltsev.com
Дата: 05.06.03 02:57
Оценка: +1
Здравствуйте, WolfHound, Вы писали:

WH>В С++ нет так называемых виртуальных конструкторов что дельфисты расценивают как большой не достаток. Но сложно ли их реализовить? НЕТ!


А можно, please, определение виртуального контруктора, а то както не понятно о чем речь

-zork
Думать надо ...головой :)
Re: Кто сказал что в С++ нет виртуальных конструкторов?
От: main  
Дата: 05.06.03 03:25
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>В С++ нет так называемых виртуальных конструкторов что дельфисты расценивают как большой не достаток. Но сложно ли их реализовить? НЕТ!

WH>[/ccode]

О чем спор, в дельфях вообще НЕТ конструкторов
Re: Кто сказал что в С++ нет виртуальных конструкторов?
От: ArtDenis Россия  
Дата: 05.06.03 04:18
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>В С++ нет так называемых виртуальных конструкторов что дельфисты расценивают как большой не достаток. Но сложно ли их реализовить? НЕТ!

WH>Пример
WH>

Ну ты и загнул... Хотя после небольшой переделки всё это работает.

Для реализации виртуального конструктора вполне достаточно (IMHO):
1. Иметь базовую виртуальную функцию для создания экземпляра класса
2. Иметь указатель на функцию создания экземпляра и инициализировать её в конструкторе наследника. Этот вариант легко и удобно реализуется при помощи шаблонов.

Кроме того, для реализации ссылки на тип, на мой взгляд, действительного приемущества Virtual Pscal'я, можно применять фабрику объектов. Я, например, использую шаблон фабрики написанной по "заветам Александреску"

Денис.
... << RSDN@Home 1.0 beta 7a >>
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[2]: Кто сказал что в С++ нет виртуальных конструкторов?
От: WolfHound  
Дата: 05.06.03 05:04
Оценка:
Здравствуйте, ZORK, Вы писали:

ZOR>А можно, please, определение виртуального контруктора, а то както не понятно о чем речь

Само название на мысли не наталкивает? Если нет то это механизм создания производных классов имея инвормацию только о базовом.
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[2]: Кто сказал что в С++ нет виртуальных конструкторов?
От: WolfHound  
Дата: 05.06.03 05:06
Оценка:
Здравствуйте, ArtDenis, Вы писали:

AD>Для реализации виртуального конструктора вполне достаточно (IMHO):

AD>1. Иметь базовую виртуальную функцию для создания экземпляра класса
ЧАВО????
AD>2. Иметь указатель на функцию создания экземпляра и инициализировать её в конструкторе наследника. Этот вариант легко и удобно реализуется при помощи шаблонов.
А я что делаю? Только надо еще функцию удаления тк это механизм планируется использовать через границу длл.

AD>Кроме того, для реализации ссылки на тип, на мой взгляд, действительного приемущества Virtual Pscal'я, можно применять фабрику объектов. Я, например, использую шаблон фабрики написанной по "заветам Александреску"

А это чем не ссылка на тип?
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[3]: Кто сказал что в С++ нет виртуальных конструкторов?
От: ZORK Россия www.zorkaltsev.com
Дата: 05.06.03 05:08
Оценка:
Здравствуйте, WolfHound, Вы писали:

ZOR>>А можно, please, определение виртуального контруктора, а то както не понятно о чем речь

WH>Само название на мысли не наталкивает? Если нет то это механизм создания производных классов имея инвормацию только о базовом.

Нет — не наталкивает , так как я привык думать что виртуальные методы определяются через vTable, которого очевидно нет, когда объект еще не создан. Но есть мнение, что за этим причудилвым названием ("виртуальный конструктор") скрывается Abstract Factory Design Pattern. Или я ошибаюсь?

-zork
Думать надо ...головой :)
Re[3]: Кто сказал что в С++ нет виртуальных конструкторов?
От: ArtDenis Россия  
Дата: 05.06.03 05:29
Оценка:
Здравствуйте, WolfHound, Вы писали:

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


AD>>Для реализации виртуального конструктора вполне достаточно (IMHO):

AD>>1. Иметь базовую виртуальную функцию для создания экземпляра класса
WH>ЧАВО????

class BASE
{
  ...
  virtual BASE* create() = 0;
  ...
};

class DERIVED
{
  virtual BASE* create() { return new DERIVED; } 
};

И никаких извращений.

AD>>Кроме того, для реализации ссылки на тип, на мой взгляд, действительного приемущества Virtual Pscal'я, можно применять фабрику объектов. Я, например, использую шаблон фабрики написанной по "заветам Александреску"

WH>А это чем не ссылка на тип?

Ссылка на тип в паскале — это один из типов данных самого языка. Т.е. эта ссылка может передаватся в функцию, по этой ссылке могут вызыватся конструкторы и т.д. Фабрика объектов — это творение самого программиста. Максимум, что она умеет — это создавать или копировать объекты. В случае с фабрикой стоит проблема регистрации объектов, если фабрика находится в dll, кроме того при созданни большого количества объектов фабрика проигрывает ссылке на тип. Когда ты используешь ссылку на тип, тебя не волнует, будет ли создан объект в Dll или в exe-шнике, главное чтобы у них был один и тот-же менеджер памяти.

PS: Не стоит рассматривать моё сообщение, как наезд на C++. Сам пишу на C++
... << RSDN@Home 1.0 beta 7a >>
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[4]: Кто сказал что в С++ нет виртуальных конструкторов?
От: WolfHound  
Дата: 05.06.03 05:38
Оценка:
Здравствуйте, ArtDenis, Вы писали:

AD>И никаких извращений.

Это работать не будет.

AD>Ссылка на тип в паскале — это один из типов данных самого языка. Т.е. эта ссылка может передаватся в функцию, по этой ссылке могут вызыватся конструкторы и т.д. Фабрика объектов — это творение самого программиста. Максимум, что она умеет — это создавать или копировать объекты. В случае с фабрикой стоит проблема регистрации объектов, если фабрика находится в dll, кроме того при созданни большого количества объектов фабрика проигрывает ссылке на тип. Когда ты используешь ссылку на тип, тебя не волнует, будет ли создан объект в Dll или в exe-шнике, главное чтобы у них был один и тот-же менеджер памяти.

Еще раз медитируем над моим текстом и говорим чем это отличается от того что ты толькочто написал. Кроме того что мне безразлично один менеджер памяти или много.
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[4]: Кто сказал что в С++ нет виртуальных конструкторов?
От: WolfHound  
Дата: 05.06.03 05:43
Оценка:
Здравствуйте, ZORK, Вы писали:

ZOR>Нет — не наталкивает , так как я привык думать что виртуальные методы определяются через vTable, которого очевидно нет, когда объект еще не создан. Но есть мнение, что за этим причудилвым названием ("виртуальный конструктор") скрывается Abstract Factory Design Pattern. Или я ошибаюсь?

В общем да. ПРосто я стремился получить максимально близкую сенематику к дельфям.
Хотя если присмотрться то шаблом Meta фактически генератор виртуальной таблици.
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[5]: Кто сказал что в С++ нет виртуальных конструкторов?
От: ZORK Россия www.zorkaltsev.com
Дата: 05.06.03 05:49
Оценка:
Здравствуйте, WolfHound, Вы писали:

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


ZOR>>Нет — не наталкивает , так как я привык думать что виртуальные методы определяются через vTable, которого очевидно нет, когда объект еще не создан. Но есть мнение, что за этим причудилвым названием ("виртуальный конструктор") скрывается Abstract Factory Design Pattern. Или я ошибаюсь?

WH>В общем да. ПРосто я стремился получить максимально близкую сенематику к дельфям.
WH>Хотя если присмотрться то шаблом Meta фактически генератор виртуальной таблици.

Понял!
Думать надо ...головой :)
Re[5]: Кто сказал что в С++ нет виртуальных конструкторов?
От: ArtDenis Россия  
Дата: 05.06.03 05:55
Оценка:
Здравствуйте, WolfHound, Вы писали:

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


AD>>И никаких извращений.

WH>Это работать не будет.
Почему ?

AD>>Ссылка на тип в паскале — это один из типов данных самого языка. Т.е. эта ссылка может передаватся в функцию, по этой ссылке могут вызыватся конструкторы и т.д. Фабрика объектов — это творение самого программиста. Максимум, что она умеет — это создавать или копировать объекты. В случае с фабрикой стоит проблема регистрации объектов, если фабрика находится в dll, кроме того при созданни большого количества объектов фабрика проигрывает ссылке на тип. Когда ты используешь ссылку на тип, тебя не волнует, будет ли создан объект в Dll или в exe-шнике, главное чтобы у них был один и тот-же менеджер памяти.

WH>Еще раз медитируем над моим текстом и говорим чем это отличается от того что ты толькочто написал. Кроме того что мне безразлично один менеджер памяти или много.

Блин, точно! Вчера тестил (и правил) твой код ночью, поэтому основной идеи и не заметил . Хотя сам бы написал немножко по-другому.
... << RSDN@Home 1.0 beta 7a >>
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[6]: Кто сказал что в С++ нет виртуальных конструкторов?
От: WolfHound  
Дата: 05.06.03 16:35
Оценка:
Здравствуйте, ArtDenis, Вы писали:

AD>>>И никаких извращений.

WH>>Это работать не будет.
AD>Почему ?
Попробуй сотвори... Узнаешь много нового о С++ и виртуальных функциях в часности. Конкретно для того чтобы была вызвана виртуальная функция класса Derived нужно иметь экземпляр класса Derived.
... << RSDN@Home 1.0 beta 6a >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[7]: Кто сказал что в С++ нет виртуальных конструкторов?
От: ArtDenis Россия  
Дата: 05.06.03 17:17
Оценка:
Здравствуйте, WolfHound, Вы писали:
WH>>>Это работать не будет.
AD>>Почему ?
WH>Попробуй сотвори... Узнаешь много нового о С++ и виртуальных функциях в часности. Конкретно для того чтобы была вызвана виртуальная функция класса Derived нужно иметь экземпляр класса Derived.

Я имел ввиду, что это нужно для копирования объекта, если мы имеем только указатель на базовый класс.
... << RSDN@Home 1.0 beta 7a >>
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re: Кто сказал что в С++ нет виртуальных конструкторов?
От: WolfHound  
Дата: 06.06.03 11:49
Оценка:
Здравствуйте, WolfHound, Вы писали:

Я тут сотворил конвертацию типов те обьект можно привести к любому типу из иерархии.
Вот я думаю оставить как сейчас
    MetaPtr<Base> ptr0=meta.Create();
    MetaPtr<Base2> ptr2=ptr0.Convert<Base2>();

или сделать не явно
    MetaPtr<Base> ptr0=meta.Create();
    MetaPtr<Base2> ptr2=ptr0;

Как лучше?
Во втором проще совершить ошибку.
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[2]: Кто сказал что в С++ нет виртуальных конструкторов?
От: WFrag США  
Дата: 06.06.03 12:21
Оценка:
Здравствуйте, WolfHound, Вы писали:

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


WH>Я тут сотворил конвертацию типов те обьект можно привести к любому типу из иерархии.

WH>Вот я думаю оставить как сейчас
WH>
WH>    MetaPtr<Base> ptr0=meta.Create();
WH>    MetaPtr<Base2> ptr2=ptr0.Convert<Base2>();
WH>

WH>или сделать не явно
WH>
WH>    MetaPtr<Base> ptr0=meta.Create();
WH>    MetaPtr<Base2> ptr2=ptr0;
WH>

WH>Как лучше?
WH>Во втором проще совершить ошибку.

Сделай с полиси, как завещал Александреску.
7. О чем невозможно говорить, о том следует молчать.
Re[3]: Кто сказал что в С++ нет виртуальных конструкторов?
От: WolfHound  
Дата: 06.06.03 13:43
Оценка:
Здравствуйте, WFrag, Вы писали:

WF>Сделай с полиси, как завещал Александреску.

А как полиси могут влиять на наличие/оттсутствие шаблонных конструкторов/операторов присваивания?
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[4]: Кто сказал что в С++ нет виртуальных конструкторов?
От: WFrag США  
Дата: 06.06.03 16:45
Оценка:
Здравствуйте, WolfHound, Вы писали:

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


WF>>Сделай с полиси, как завещал Александреску.

WH>А как полиси могут влиять на наличие/оттсутствие шаблонных конструкторов/операторов присваивания?

Я не спец в этом вопросе, но по-моему в SmartPtr что-то похожее есть.

Далее — обрывки мыслей на тему, как можно влиять на наличие конструкторов/операторов присваивания (Для произвольного типа в правой части. Если нужно разрешать/запрещать, когда справа только MetaPtr, то все проще), причем если преобразование запрещено, то компилятор говорит, что преобразования нет (в SmartPtr, вроде бы, выдается, например, что нельзя одно полиси в другое преобразовать):

I. Первая идея:

Сделать базовую реализацию.

class MetaPtrBase<...>
{
    // ...
};


Далее делаем так:

template <bool allow>
class MetaPtr;

template<>
class MetaPtr<true> : public MetaPtrBase
{
    // Здесь придется написать все конструкторы,
    // плюс те, которые разрешаются данной полиси==true
    // (в данном случае роль полиси играет flag)
};

template<>
class MetaPtr<false> : public MetaPtrBase
{
    // Здесь нужно придется все конструкторы,
    // кроме тех, которые запрещаются данной полиси==false
    // (в данном случае роль полиси играет flag)
};


В случае с операторами присваивания попроще будет, они наследуются.

II. Второй вариант:

Можно попробовать поиграться с Loki::Select, выбирая либо нормальный тип параметра конструктора, либо фиктивный. При этом придется делегировать конструирование некой функции. Что-то вроде:

template<bool allow>
class MetaPtr
{
template<bool allow>
class Test
{
private:
    class Dummy
    {
    };
public:
    Test( typename Loki::Select<allow, /*Нужный тип параметра*/, Dummy>::Result param )
    {
        _construct( param );
    }
private:
    void _construct( /*Нужный тип параметра*/ param )
    {
        // нужные действия
    }

    void _construct( Dummy param )
    {
    }
}


Первый вариант плох тем, что при увеличении количества всяких полиси подобного типа возможен комбинаторный взрыв специализаций классов MetaPtr (собирать набор конструкторов из разных классов нельзя — они не наследуются, а другого варианта я не вижу).

А второй вариант, похоже, не прокатывает для шаблонных конструкторов (которые, собственно, и нужны) .


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

Вот такие вот мысли.
7. О чем невозможно говорить, о том следует молчать.
Re: Кто сказал что в С++ нет виртуальных конструкторов?
От: Alexey Shirshov Россия http://wise-orm.com
Дата: 08.06.03 10:16
Оценка: 12 (2) +1
Здравствуйте, WolfHound, Вы писали:

Опять извращение.
У меня оно даже не скомпилялось (VS 7.0)

И чем это отличается от
using std::cout;
using std::endl;

class Base
{
public:
    virtual void Hello() const
    {
        cout << "Base: Hello!" << endl;
    }
};

class Derived : public Base
{
public:
    void Hello() const
    {
        cout << "Derived: Hello!" << endl;
    }
};

class SomeOther
{
};

template<class T>
Base* CreateCLS(void)
{
    return new T();
}

int _tmain()
{
    std::auto_ptr<Base> c(CreateCLS<Derived>());
    c->Hello();
    
    //error
    //std::auto_ptr<Base> c(CreateCLS<SomeOther>());
    return 0;
}


ИМХО, ты не достаточно четко представляешь себе этот паттерн. Его идея очень проста: не прошивать в коде создание конкретных классов. Созданием объектов должно быть сгруппировано в одном месте для того, чтобы не приходилось вносить большое кол-во изменений в код. Например
class Saver
{
public:
    virtual void Save(void) = 0;
};

Saver* CreateSaver(bool fToDisk = true);

class SaverToDisk : public Saver
{
    friend Saver* CreateSaver(bool fToDisk);
protected:
    SaverToDisk(){}
private:
    void Save(void)
    {
        cout << "save to disk" << endl;
    }
};

class SaverToPipe : public Saver
{
    friend Saver* CreateSaver(bool fToDisk);
protected:
    SaverToPipe(){}
private:
    void Save(void)
    {
        cout << "save to pipe" << endl;
    }
};

Saver* CreateSaver(bool fToDisk = true)
{
    if (fToDisk)
        return new SaverToDisk();
    else
        return new SaverToPipe();
}

int _tmain()
{
    std::auto_ptr<Saver> s(CreateSaver(false));
    s->Save();
    return 0;
}


В программе используется интерфейс Saver, а создание происходит только в одном месте. Можно убрать параметр и захардкодить конктерный объект в CreateSaver.
Еще заметь, реализация методов закрыта (private), а конструкторы защищены. Нужно это для того, чтобы клиент не мог создать классы реализации даже если чего-то про них пронюхает.
Все это хозяйство выноситься в отдельный модуль и наступает счастье.
Re[2]: Кто сказал что в С++ нет виртуальных конструкторов?
От: WolfHound  
Дата: 08.06.03 20:27
Оценка:
Здравствуйте, Alexey Shirshov, Вы писали:

AS>Опять извращение.

Опять не разобравшись критикуешь.
AS>У меня оно даже не скомпилялось (VS 7.0)
А я разве обещал? Скоро выложу значительно доработаную версию с конвертацией типов и клонированием.
AS>И чем это отличается от
Тем что DoSome может лежать в другой длл. Плюс я могу накидать еще длл которые будут содержать другие реализации причем длл с DoSome не надо перекомпилировать.

AS>ИМХО, ты не достаточно четко представляешь себе этот паттерн.

Вот не надо что такое фабрика классов я знаю очень хорошо. Тут ставилась немного другая задача.

AS>В программе используется интерфейс Saver, а создание происходит только в одном месте.

А я могу создавать где угодно и какие угодно причем без ПЕРЕКОМПИЛЯЦИИ что не моловажно когда колличество длл зашкаливает за 10.
AS>Еще заметь, реализация методов закрыта (private), а конструкторы защищены. Нужно это для того, чтобы клиент не мог создать классы реализации даже если чего-то про них пронюхает.
Ты меня за кого держишь?
AS>Все это хозяйство выноситься в отдельный модуль и наступает счастье.
... << RSDN@Home 1.0 beta 6a >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.