Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > неявное преобразование типов


Автор: zss 6.6.2006, 14:07
есть классы (могут быть ошибки - писал здесь, но думаю смысл понятен)
Код

class Item
{
...
int size () const;
Item& operator = (int rhs);
...
}

class Items{
    Item item_;
    operator const Item& () const {return item_;}
    operator Item& () {return item_;}
}


но я не могу использовать оператор
Код

Items items;
int k = items.size();
items = 100;


почему ? ведь оператор определен
Код

    operator Item& () {return item_;}
    operator const Item& () const {return item_;}
 

Автор: LPBOY 6.6.2006, 14:38
Цитата(zss @  6.6.2006,  14:07 Найти цитируемый пост)
items = 100;

В таких случаях, для операторов-мемберов, никогда не происходят преобразования. Если у Items нет подходящего оператора=, то просто выдается ошибка. Преобразование произошло бы, если бы мог существовать глобальный оператор Item& operator=(Item& lhs, int rhs){...}. smile 

Автор: zss 6.6.2006, 15:09
Цитата(LPBOY @  6.6.2006,  14:38 Найти цитируемый пост)
В таких случаях, для операторов-мемберов, никогда не происходят преобразования. Если у Items нет подходящего оператора=, то просто выдается ошибка.


в самом деле это я привел только пример. На самом деле методов больше и их не получиться реализовать через опереторы. Более того не хотелось бы плодить один и тот же код.


Цитата(LPBOY @  6.6.2006,  14:38 Найти цитируемый пост)
Преобразование произошло бы, если бы мог существовать глобальный оператор Item& operator=(Item& lhs, int rhs){...}


этого тоже не очень хочется делать

Может есть способ проще - что-нибудь с proxy-классами. Или как еще заставить неявно преобразовать типы smile
 

Автор: MAKCim 6.6.2006, 16:22
Цитата

int k = items.size();

в C++ нет перегрузки operator.()

Добавлено @ 16:29 
Цитата

в самом деле это я привел только пример. На самом деле методов больше и их не получиться реализовать через опереторы. Более того не хотелось бы плодить один и тот же код.

попробуй через operator->()
Код

class Item
{
...
int size () const;
Item& operator = (int rhs);
...
};

class Items{
    Item* item_;
public:
    Items(): item_(new Item) {}

    Item* operator->() {return item_;}
    const Item* operator->() const {return item_;}
};

но тогда станут доступны через operator->() все public методы Item-а 

Автор: MAKCim 6.6.2006, 16:48
Код

class Item
{
...
int size () const;
Item& operator = (int rhs);
...
};
class Items{
    Item item_;
private:
    class proxy: public Item
    {
    private:
         Item& obj;
    private:
         void set_ref() {obj=*this;}
         void set_obj() {static_cast<Item&>(*this)=obj;}

        // Тут using-ом можно запрещать методы Item-а
    public:
         proxy(Item& p_obj): obj(p_obj) {set_obj();}
         ~proxy() {set_ref();}
    };
public:
    proxy get() {return proxy(item_);}
};
  

Автор: Earnest 6.6.2006, 18:16
MAKCim, мне кажется, первый вариант лучше (только там никто не заставлет указатель хранить, можно и прямо объект). Применение прокси вроде ничем не оправд
ано.
Цитата(MAKCim @  6.6.2006,  17:22 Найти цитируемый пост)
но тогда станут доступны через operator->() все public методы Item-а  

Так этого zss и добивается - получить доступ к открытым членам Item.
Есть еще вариант с оператором () (если указательная семантика не нравится).

Код

class Items{
    Item item_;
public:
    // ...
    Item& operator()() {return item_;}
    const Item& operator()() const {return item_;}
};

Items items;
int k = items().size();
 

Автор: MAKCim 6.6.2006, 19:39
Цитата

только там никто не заставлет указатель хранить, можно и прямо объект

можно  smile 
Цитата

Применение прокси вроде ничем не оправд
ано.

Код

...
Items items;
delete items.operator->();

 smile 
кроме того есть возможность ограничить использование некоторых методов Item-а (хотя может это и не нужно) 

Автор: Earnest 6.6.2006, 19:56
Цитата(MAKCim @  6.6.2006,  20:39 Найти цитируемый пост)
delete items.operator->();

Против таких программистов вообще защиты нет. Только убивать в младенчестве. smile 
Это я к тому, что дизайн должен скорее явно декларировать намерения автора, чем защищать от злонамеренного дурака. 

 

Автор: MAKCim 6.6.2006, 21:02
Цитата

Это я к тому, что дизайн должен скорее явно декларировать намерения автора, чем защищать от злонамеренного дурака. 

Это да
просто в принципе такое можно сделать 

Автор: zss 7.6.2006, 08:03
что-то не очень помагает

если быть точным, то весь код примерно такой
Код

class Item
{
    ...
    int size(void) const;
    Item& operator += (size_t rhs);
    ...
}

typedef std::map<int, Item> pack_map;
typedef pack_map::const_iterator it_pack;

class Some
{
private :
    pack_map items_;

    class ItemProxy {
    private :
        friend class Some;
        pack_map& map_;

        explicit ItemProxy (pack_map& map) : map_ (map) {;}
        ItemProxy& operator = (const ItemProxy&);
        ItemProxy& operator += (const ItemProxy& rhs);

        class Proxy {
        private :
            friend class ItemProxy;
            pack_map& map_;
            int key_;

            Proxy (pack_map& map, int key)
                : map_(map), key_(key){;}
            Proxy& operator = (const Proxy&);

        public :
            Item& operator () (void);
            const Item& operator () (void) const;

        };

    public :
        Proxy operator [] (int key);
        const Proxy operator [] (int key) const;
    };

public :

    ItemProxy items;
}


и тогда
Код

    Some some;
    some.items[0].size(); // ошибка
    some.items[0] += 10;  // ошибка
 

Автор: Earnest 7.6.2006, 08:17
Опять на те же грабли наступаешь... Оператор преобразования типа здесь не поможет... И вообще, не стоит им злоупотреблять: в данном контексте его применение неоправданно.
Короче, прямо по Items (без скобок (), -> или функции get(), как в примере MAKCima, получить доступ к элементам Item не получится. Потому что компилятор не будет применять преобразование типа к левому операнду "[]",".", etc. 

Автор: zss 7.6.2006, 08:42
Earnest, блин...

но ведь делают как-то. Например многие библиотеки в Builder именно так и работают

Значит можно извратиться smile

Добавлено @ 08:44 
Цитата(MAKCim @  6.6.2006,  16:22 Найти цитируемый пост)
попробуй через operator->()


не хотелось бы так делать - не совсем понятно (интуитивно) для пользователей 

Автор: MAKCim 7.6.2006, 09:13
Цитата

не хотелось бы так делать - не совсем понятно (интуитивно) для пользователей  

а это интуитивно понятно что-ли?
Цитата

int k = items.size();

непонятно что за size() есть у Items
Цитата

Значит можно извратиться 

если Items непременно должен себя вести как Item
может использовать наследование?
или это логически/семантически/... не верно будет?
 

Автор: zss 7.6.2006, 11:05
Цитата(MAKCim @  7.6.2006,  09:13 Найти цитируемый пост)
непонятно что за size() есть у Items


в последнем примере есть операторы [] - поэтому сразу понятно, что это массивы 

Автор: Earnest 7.6.2006, 13:36
Цитата(zss @  7.6.2006,  09:42 Найти цитируемый пост)
Например многие библиотеки в Builder именно так и работают

Скорее всего это ты что-то не так понял: или наследование, 
или переопределение необходимых операторов\функций делегированием ([], size(), etc). 

Автор: GremlinProg 7.6.2006, 14:29
Код

TYPE&GetMember(size_t id){
  //возвращаем референс объекта
}
const TYPE&GetMember(size_t id)const{
  //возвращаем константный референс объекта
}
__declspec(property(get=GetMember))
TYPE  members[];

Использовать можно, например, так:
Код

object.members[5].x = 0;
int a = object.members[5].x;

И не нужно дополнительных классов описывать, только длину нужно вывести в отдельное свойство.

PS: Такая каркасная архитектура поддерживается в VC 7.1, другие не проверял 

Автор: zss 7.6.2006, 15:49
GremlinProg, на сколько я знаю __declspec это примочка M$ 

Автор: GremlinProg 14.6.2006, 17:54
на сколько я знаю __declspec это примочка Visual Studio, по крайней мере с 6-й версии, по моему это уже казано в PS 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)