Re[8]: Перегрузка операторов
От: Кодт Россия  
Дата: 23.05.04 20:18
Оценка: 40 (3)
Здравствуйте, Red Line, Вы писали:

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


RL>
  >>class A
A>>    {
A>>        public:
A>>            operator int()
A>>//------------------ >> А где здесь оператор? operator - ключевое слово
A>>                {                                                     int - встроенный в комплятор тип данных
A>>                    return 15;                  Выходит что () есть обозначение оператора приведения типа? 
A>>                }
A>>    };
A>>//
A>>A a;
A>>int x = a; // x будет иметь значение 15.
RL>

RL>Почему x будет иметь значение 15? Здесь же участвует operator =, как это работает?

Давай разбираться в синтаксисе.
Операторы бывают: членами класса (методами) и внешними
class C
{
public:
  result_type operator ??? (arguments) .....
};
result_type operator !!! (arguments) .....

Посмотрим, как выглядят операторы-члены.
1) инфиксные двухместные (например, x+y). При этом левый аргумент (подразумеваемый) — это сам объект, а правый указывается в сигнатуре. Сравни:
class C
{
public:
    // функциональная форма
  static C add(const C& lhs, const C& rhs);
  static C subtract(const C& lhs, const C& rhs);

  C operator + (const C& rhs) const { return add( *this, rhs ); }
};
C operator - (const C& lhs, const C& rhs) { return C::subtract(lhs, rhs); }

2) одноместные префиксные (например, -x, ~x, !x). Единственный аргумент (подразумеваемый) — это сам объект.
class C
{
public:
  static C minus(const C& arg);
    static C invert(const C& arg);
    
    C operator - () const { return negate(*this); }
};
operator !(const C& arg) { return C::minus(arg); }

3) автоинкремент, автодекремент. Бывает как префиксным, так и постфиксным. ++x, x++. Чтобы отличать, у постфиксного есть фиктивный правый аргумент типа int.
class C
{
public:
    C& operator ++ (); // обычно результат пред-инкремента - это сам объект (модифицированный)
    C operator ++ (int) // а результат пост-инкремента - копия объекта до модификации
    {
        // типичная реализация пост-инкремента выглядит так (если, конечно, оператор не несёт иной смысловой нагрузки)
        C temp = *this;
        ++(*this);
        return temp;
    }
};
// внешние операторы - аналогичны
C& operator --(C& arg);
C operator --(C& arg, int) { C temp = arg; --arg; return temp; }

4) оператор индекса x[y] -- двухместный, левый аргумент это x, правый — y. Всё аналогично инфиксным.
5) оператор функции x(y,z,t.....) -- многоместный. Левый аргумент — x — это объект. Правые аргументы — y,z,t.... Причём количество их (от 0) и типы могут быть любыми.
6) оператор приведения типа (some_type)x -- одноместный, префиксный оператор. В роли some_type могут быть и простые типы (например, int), и имена типов (LPCSTR), и выражения типов (char const*).
class C
{
public:
  operator const char* () const;
    // обрати внимание: тип возвращаемого значения совпадает с именем оператора, т.е. здесь const char*
};

7) операторы присваивания, x=y, x+=y и т.п. Это инфиксные операторы. Перекрытый x=y не может быть внешним, — только членом класса.

При вызове оператора присваивания можно помыслить, будто это обычная функция.
class A;
class B;

class C
{
public:
    void operator = (const A& rhs);
    void operator = (const C& rhs);
    ...
};
class D
{
public:
    operator A () const;
    operator B () const;
    ...
};

main()
{
    C c;
    D d;
    c = d;
}

Компилятор попытается найти наилучшую (самую короткую) форму для (c=d). При этом если нет оператора, принимающего на вход D, D&, const D&, то он попробует выполнить преобразования d к типам, объявленным в сигнатурах:
* есть ли операторы приведения типа: (A)d, (const A&)d, (C)d, (const C&)d
* есть ли конструкторы A(const D&), C(const D&)
В случае более чем одного равновозможного преобразования, компилятор выдаст ошибку.
В случае, если возможных преобразований нет — будет другая ошибка.
... << RSDN@Home 1.1.2 stable >>
Перекуём баги на фичи!
Re[4]: Перегрузка операторов
От: Павел Кузнецов  
Дата: 23.05.04 22:47
Оценка: 9 (1)
> ПК> Предопределенные операторы для встроенных типов функциями не являются. В частности, нельзя взять их адрес, они не окружены точками следования и т.п.
>
> А конструкторы/деструкторы/присваивания POD-типов — тоже?

Конструкторы/деструкторы есть не у всех POD-типов, а только у классов. У классов конструкторы, деструкторы и оператор присваивания функциями являются в том смысле, что они окружены точками следования и т.п. Хотя адрес конструктора или деструктора получить нельзя.

> Наверное, имеет смысл говорить о функциях и псевдофункциях.

> (Хотя такого термина и нет в Стандарте, но для единообразия можно ввести)...

Конструкторы/деструкторы стандарт называет специальными функциями.
Posted via RSDN NNTP Server 1.9 alpha
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[5]: Перегрузка операторов
От: adontz Грузия http://adontz.wordpress.com/
Дата: 23.05.04 23:26
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Конструкторы/деструкторы есть не у всех POD-типов, а только у классов. У классов конструкторы, деструкторы и оператор присваивания функциями являются в том смысле, что они окружены точками следования и т.п.


А что это такое — точка следования? Первый раз слышу

ПК>Хотя адрес конструктора или деструктора получить нельзя.


Кстати я так и не понял почему Этому есть какое-нибудь объяснение или просто так решили?
A journey of a thousand miles must begin with a single step © Lau Tsu
Re[6]: Перегрузка операторов
От: Павел Кузнецов  
Дата: 24.05.04 05:15
Оценка: 10 (1)
> ПК>Конструкторы/деструкторы есть не у всех POD-типов, а только у классов. У классов конструкторы, деструкторы и оператор присваивания функциями являются в том смысле, что они окружены точками следования и т.п.
>
> А что это такое — точка следования? Первый раз слышу

Например:
http://rsdn.ru/Forum/Message.aspx?mid=94162&amp;only=1
Автор: Павел Кузнецов
Дата: 02.09.02

http://rsdn.ru/Forum/Message.aspx?mid=521301&amp;only=1
Автор: Павел Кузнецов
Дата: 28.01.04


> ПК>Хотя адрес конструктора или деструктора получить нельзя.

>
> Кстати я так и не понял почему Этому есть какое-нибудь объяснение или просто так решили?

Об этом чуть позже, если будет время.
Posted via RSDN NNTP Server 1.9 alpha
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[4]: Перегрузка операторов
От: jazzer Россия Skype: enerjazzer
Дата: 24.05.04 12:08
Оценка: +1
Здравствуйте, adontz, Вы писали:

ПК>>Оператора присваивания здесь нет. Здесь есть инициализация. Это суть разные вещи.


A>Для классов да, но разве для POD типов это не присваивание? Я долго читал раздел 8.5 стандарта (ИМХО на редкость непонятный) и понял именно так. :xz:


То, что это инициализация, напрямую следует из грамматики:
simple-declaration:
   decl-specifier-seq opt init-declarator-list opt ;

init-declarator:
   declarator initializer opt

initializer:
   = initializer-clause
   ( expression-list )

Так что любая запись вида
тип имя = что-то;

являет собой объявление с инициализацией.

И POD-овость типа тут вообще ни причем.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[9]: Перегрузка операторов
От: Red Line  
Дата: 24.05.04 13:22
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Давай разбираться в синтаксисе.

Давай...

К>Операторы бывают: членами класса (методами) и внешними — понял.

К>
К>class C
К>{
К>public:
К>  result_type operator ??? (arguments) ..... - этот оператор член класса.
К>};
К>result_type operator !!! (arguments) ..... - а это внешний оператор.
К>

К>Посмотрим, как выглядят операторы-члены.
К>1) инфиксные двухместные (например, x+y). При этом левый аргумент (подразумеваемый) — это сам объект, а правый указывается в сигнатуре. Сравни:

Перевидте пожалуйста ... Что значит инфиксные и префиксные, одноместные и двухместные. Смутно очень понимаю ...

К>
К>class C
К>{
К>public:
К>    // функциональная форма
К>  static C add(const C& lhs, const C& rhs);-----------------------> Это функция
К>  static C subtract(const C& lhs, const C& rhs);

К>  C operator + (const C& rhs) const { return add( *this, rhs ); } --------------> Это оператор.


По моему мнению у оператора + должно быть два входных параметра и возвращаемое значение.
Т.е С operator + (const& lhs, const& rhs){return add(lhs, rhs);}
Ваша запись:
C operator + (const C& rhs) const { return add( *this, rhs ); }
мне не понятна.
Вы пишите : "инфиксные двухместные (например, x+y). При этом левый аргумент (подразумеваемый) — это сам объект, а правый указывается в сигнатуре."
Можно ли это читать так: .... м-да.... кажись понял ))) Т.е одно слагаемое здесь всегда постоянно (это сам объект), а другое передаётся через параметр. Так?
(const C& rhs) — правый аргумент, единственное слагаемое которое будет складыватся с объектом;
{ return add( *this, rhs ); } — тело оператора, в котором *this — и есть тот самый подразумеваемый левый аргумент;
Правильно?
Одно не могу понять — что занчит const? К чему он относится (это специальное слово говорящее, что переменная перед которой оно поставлено будет доступна только для чтения — это так я понимаю эту запись) Зачем оно здесь? К чему оно относится и как?

К>C operator — (const C& lhs, const C& rhs) { return C::subtract(lhs, rhs); }


А эта запись мне понятна. Тут разность вычисляется методом класса C::subtract(lhs, rhs)
и возвращается из оператора.

К>2) одноместные префиксные (например, -x, ~x, !x). Единственный аргумент (подразумеваемый) — это сам объект.

К>
К>class C
К>{
К>public:
К>  static C minus(const C& arg);
К>    static C invert(const C& arg);
    
К>    C operator - () const { return negate(*this); }


Правильно ли это читать так:
Если "-" будет поставлен перед переменной типа С (аргументов то никаких нет ) значит отработает вот этот код:

return negate(*this);

Т.е

C x;
C y = -x;

Если оператор это функция, то эта запись должна быть аналогична следующей:

C x;
C y = -()x; //Как это будет работать Вот если так -(x); то логически мне понятно,- проясните плиз в чём я не прав


К>operator !(const C& arg) { return C::minus(arg); }-


причём тут minus(arg) — здесь по идее должна быть инверсия Да и к тому же в заголовке
этого пункта Вы говорите "Единственный аргумент (подразумеваемый) — это сам объект." Тогда это что — const C& arg, это же агрумент

Здесь мне кажется какая-то путанится.... Поясни (перепиши) елси я прав...

К>3) автоинкремент, автодекремент. Бывает как префиксным, так и постфиксным. ++x, x++. Чтобы отличать, у постфиксного есть фиктивный правый аргумент типа int.-------->>


Он всегда имеет тип int чтобы отличался от прификсного чисто визуально?
Впрочем если не считать того, что я не сумел понять из предыдущего пункта, то этот мне в принципе понятен.

Исправлено форматирование, удалено избыточное цитирование. -- ПК
Re[10]: Перегрузка операторов
От: jazzer Россия Skype: enerjazzer
Дата: 24.05.04 14:16
Оценка: +2 :)
Здравствуйте, Red Line, Вы писали:

RL>Перевидте пожалуйста ... Что значит инфиксные и префиксные, одноместные и двухместные. Смутно очень понимаю ...


инфиксный — это значит, что символ операции стоит между своими аргументами.
префиксный, соответственно — перед, постфиксный — после.

например, сложение можно было бы записать тремя способами (не С++!): +(x,y), (x,y)+, x+y (пре-, пост- и инфиксная нотация соответственно).
Например, в С++ для сложения используется инфиксная форма, для унарного минуса -х — префиксная, для оператора вызова функции х() — постфиксная, для инкремента — и префиксная ++х, и постфиксная х++.

RL> (const C& rhs) — правый аргумент, единственное слагаемое которое будет складыватся с объектом;

RL> { return add( *this, rhs ); } — тело оператора, в котором *this — и есть тот самый подразумеваемый левый аргумент;
RL> Правильно?

Правильно

RL> Одно не могу понять — что занчит const? К чему он относится (это специальное слово говорящее, что переменная перед которой оно поставлено

RL> будет доступна только для чтения — это так я понимаю эту запись) Зачем оно здесь? К чему оно относится и как?

Поскольку речь идет о функции-члене, которая будет вызвана для какого-то объекта, то этот const означает, что сам объект (*this) внути этой функции будет константным.

RL>Если оператор это функция, то эта запись должна быть аналогична следующей:


RL>C x;

RL>C y = -()x; //Как это будет работать :???: Вот если так -(x); то логически мне понятно,- проясните плиз в чём я не прав :???:

почти так.
если ты хочешь явно использовать функциональную форму вызова оператора, то должен писать так:
C y = operator-(x); // C y = -x;
C y = operator+(a,b); // C y = a+b;


Censored. П. 5. -- ПК
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[10]: Перегрузка операторов
От: Кодт Россия  
Дата: 24.05.04 14:17
Оценка: 21 (1)
Здравствуйте, Red Line, Вы писали:

RL>Перевидте пожалуйста ... Что значит инфиксные и префиксные, одноместные и двухместные. Смутно очень понимаю ...


По количеству операндов (аргументов) операторы бывают:
  • одноместные, унарные: -x, x++, (type)x
  • двуместные, бинарные: x*y, x[y]
  • трёхместные, тернарные: x?y:z
  • многоместные: в С++ это оператор вызова функции, f(x,y,z,t....).
    По расположению операндов:
  • префиксные — перед операндом: -x, ++x, (type)x
  • инфиксные — между операндами: x+y, x?y:z
  • постфиксные — после операнда: x++
    Принято считать, что операторы со скобками — () и [] — постфиксные. Впрочем, хоть горшком назови...

    К>>class C
    К>>{
    К>>public:
    К>>    // функциональная форма
    К>>  static C add(const C& lhs, const C& rhs);-----------------------> Это функция
    К>>  static C subtract(const C& lhs, const C& rhs);
    
    К>>  C operator + (const C& rhs) const { return add( *this, rhs ); } --------------> Это оператор.


    RL>По моему мнению у оператора + должно быть два входных параметра и возвращаемое значение.

    RL>Т.е С operator + (const& lhs, const& rhs){return add(lhs, rhs);}
    RL>Ваша запись:
    RL>C operator + (const C& rhs) const { return add( *this, rhs ); }
    RL>мне не понятна.
    RL>Вы пишите :
    RL>"инфиксные двухместные (например, x+y). При этом левый аргумент (подразумеваемый) — это сам объект, а правый указывается в сигнатуре."
    RL>Можно ли это читать так: .... м-да.... кажись понял ))) Т.е одно слагаемое здесь всегда постоянно (это сам объект), а другое передаётся через параметр. Так?
    RL>(const C& rhs) — правый аргумент, единственное слагаемое которое будет складыватся с объектом;
    RL>{ return add( *this, rhs ); } — тело оператора, в котором *this — и есть тот самый подразумеваемый левый аргумент;
    RL>Правильно?
    RL>Одно не могу понять — что занчит const? К чему он относится (это специальное слово говорящее, что переменная перед которой оно поставлено будет доступна только для чтения — это так я понимаю эту запись) Зачем оно здесь? К чему оно относится и как?

    Пожалуйста, воздержись от вставки рассуждений в текст программы. В форуме это смотрится ужасно.

    Если оператор объявляется как член класса, то самый левый его операнд — это объект данного класса, то есть *this.
    Я специально проиллюстрировал, как оператор можно реализовать через функцию.
    Если у нас есть функция add(lhs,rhs), то оператор-член выглядит как
     C  C::operator+ (const C& rhs) const { return add(*this,rhs); }

    а внешний
     C  ::operator+ (const C& lhs, const C& rhs) { return add(lhs,rhs); }


    Что значит const после списка параметров метода (будь то оператор или обычная функция)?
    Это способ сообщить, что this в контексте данного метода имеет тип const C*, то есть в этом методе объект не меняется.
    Опять же, сравни оператор-член и внешний.

    Почему оператор сложения должен быть константным?
    На самом деле, не должен. Но обычно операция сложения не меняет операнд. (x=y+z), y до и после сложения не меняется.

    Обычно операторы перекрывают, сохраняя их смысл над новыми множествами аргументов.
    То есть + это сложение (для строк — конкатенация),
    ! это отрицание (проверка на ноль, на пустоту, на бессодержательность),
    ++ это инкремент и т.д.

    Иногда перекрытому оператору даётся иной смысл, меняющий и правила (но не синтаксис) его использования.
    Например, операторы арифметического сдвига:
    unsigned int operator<< (unsigned int x, unsigned int n);
    unsigned int operator>> (unsigned int x, unsigned int n);

    (x<<n) = x*(2^n)
    (x>>n) = x/(2^n)
    где ^ — возведение в степень.
    А те же операторы, применённые к файловым потокам:
    ostream& operator<< (ostream& ostr, T value);
    istream& operator>> (istream& istr, T& value);

    означают запись в поток (модификация левого операнда!) и чтение из потока (модификация обоих операндов!)...

      
    К>>};
    К>>C operator - (const C& lhs, const C& rhs) { return C::subtract(lhs, rhs); }

    RL>А эта запись мне понятна. Тут разность вычисляется методом класса C::subtract(lhs, rhs)
    RL>и возвращается из оператора.

    К>>2) одноместные префиксные (например, -x, ~x, !x). Единственный аргумент (подразумеваемый) — это сам объект.

    К>>
    К>>class C
    К>>{
    К>>public:
    К>>  static C minus(const C& arg);
    К>>    static C invert(const C& arg);
        
    К>>    C operator - () const { return negate(*this); }
    
    
    К>>};

    RL>Правильно ли это читать так:
    RL>Если "-" будет поставлен перед переменной типа С (аргументов то никаких нет ) значит отработает вот этот код:
    RL>return negate(*this);

    RL>Т.е
    RL>C x;
    RL>C y = -x;

    Именно так.

    RL>Если оператор это функция, то эта запись должна быть аналогична следующей:

    RL>C x;
    RL>C y = -()x;

    RL>Как это будет работать Вот если так -(x); то логически мне понятно,- проясните плиз в чём я не прав
    Синтаксис операторов — перекрытых или неперекрытых — жёстко определён языком. Конструкция -()x синтаксически неверна, вне зависимости от типа аргумента.

    Всего существуют 2 формы: операторная (как обычно) и функциональная (как бы вызов функции).

    Касательно — и ! это выглядит так:
    y = x.operator-();    y = -x;
    y = operator!(x);     y = !x;


    К>>operator !(const C& arg) { return C::minus(arg); }

    — причём тут minus(arg) — здесь по идее должна быть инверсия
    Ну перепутал, бывает

    RL> Да и к тому же в заголовке этого пункта Вы говорите "Единственный аргумент (подразумеваемый) — это сам объект." Тогда это что — const C& arg, это же агрумент


    Дык это же внешний оператор. Не хотел лишний раз повторяться.
    А у оператора-члена аргумент подразумеваемый, поэтому в списке явных аргументов — пусто.

    К>>3) автоинкремент, автодекремент. Бывает как префиксным, так и постфиксным. ++x, x++. Чтобы отличать, у постфиксного есть фиктивный правый аргумент типа int.-------->>


    RL>Он всегда имеет тип int чтобы отличался от прификсного чисто визуально?


    Да, всегда. И обычно принимает значение 0.
    То есть если ты напишешь
    class C
    {
    public:
      void operator++(int t) { cout<<"postfix increment (" << t << ")"; }
      // наплевать на возвращаемое значение
    };
    
    main()
    {
      C c;
      c++;
    }

    то увидишь 0.

    RL>Впрочем если не считать того, что я не сумел понять из предыдущего пункта, то этот мне в принципе понятен.

  • Перекуём баги на фичи!
    Re[6]: Перегрузка операторов
    От: Павел Кузнецов  
    Дата: 24.05.04 15:08
    Оценка: 22 (2)
    > ПК>Хотя адрес конструктора или деструктора получить нельзя.
    >
    > Кстати я так и не понял почему Этому есть какое-нибудь объяснение или просто так решили?

    Простой пример:
    struct V
    {
       V(int) { }
       virtual ~V() { }
    };
    
    struct D : virtual V
    {
       D(int i) : V(i) { }
    };
    
    struct M : D
    {
       M(int i) : V(i), D(i) { }
    };
    
    int main()
    {
       M m(10);
    }

    Вот как выглядит код, порожденный компилятором для создания объекта m:
    ; 19   :   M m(10);
    
        push    1
        push    10                    ; 0000000aH
        lea    ecx, DWORD PTR _m$[ebp]
        call    ??0M@@QAE@H@Z                ; M::M

    Обрати внимание на выделенную строку — это специальный внутренний параметр конструктора M, нужный компилятору для того, чтобы он не инициализировал виртуальную базу несколько раз; аналогичный параметр есть и у конструктора D. Это далеко не единственный случай, когда компилятору нужно передавать в конструктор контекст из места вызова. Также компилятору может потребоваться иметь какие-то специальные внутренние значения, возвращаемые реализацией из конструктора. Примерно то же самое и с деструкторами — компилятору нужно организовывать специальное взаимодействие с управлением памятью.

    Очевидно, что "указатель на конструктор" указателем на член быть не может, т.к. объекта, который нужен для вызова функции через указатель на член, в момент "вызова" конструктора еще не существует. Кроме того, семантика "указателей на конструкторы" отличалась бы от указателей на члены: например, в отличие от указателей на члены, "указатель на конструктор" нельзя было бы приводить к "указателю на конструктор унаследованного класса", т.к., в отличие от функций-членов, конструкторы не наследуются.

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

    Таким образом, либо нужно вводить специальный синтаксис для объявления "указателей на конструкторы", либо компилятор должен генерировать специальные переходники, являющиеся обычными функциями. Также, для того, чтобы обеспечить саму возможность получения "указателя на конструктор", нужно будет вводить какие-то специальные правила, т.к. в текущей спецификации языка, у конструкторов нет имен, чтобы они не перекрывали имя класса в его определении.

    И это только самая вершина айсберга...

    Итак, в готовом виде такой сущности как указатели на конструкторы и деструкторы в языке нет, т.к. в общем случае нет какой-то готовой функции, на которую можно было бы выдать указатель пользователю. А так как пока не был продемонстрирован сценарий, в котором они были бы полезны, то и морочиться с описанием их семантики (которую без реальных сценариев использования представить невозможно) никто не стал.
    Posted via RSDN NNTP Server 1.9 alpha
    Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
    Re[7]: Перегрузка операторов
    От: adontz Грузия http://adontz.wordpress.com/
    Дата: 24.05.04 20:46
    Оценка:
    Здравствуйте, Павел Кузнецов, Вы писали:

    ПК>Таким образом, либо нужно вводить специальный синтаксис для объявления "указателей на конструкторы",


    Спаси и созрани нас от этого

    ПК>либо компилятор должен генерировать специальные переходники, являющиеся обычными функциями.


    Это УЖЕ есть! Посмотри например код функции _initterm в VC. Она вызвает функции-заглушки вызывающие конструкторы глобальных объектов.
    В принципе это было бы абсолютно аналогично placement new, за тем простым исключением, что был бы адрес. Адрес равный NULL если конструктора нет и чему-то если есть. В конце концов адрес автоматически генерирующегося оператора присваивания получить можно, так что опять таки не проблема.

    Но главное! Деструктор-то вызывается в контексте уже созданного объекта! И виртуальными функциями всё ОК. Если я ещё соглашусь, что для получения адреса конструктора нужны дополнительные усилия, то деструктор ИМХО ничем от простого метода без параметров не отличается. Или я не прав?

    ПК>Также, для того, чтобы обеспечить саму возможность получения "указателя на конструктор", нужно будет вводить какие-то специальные правила, т.к. в текущей спецификации языка, у конструкторов нет имен, чтобы они не перекрывали имя класса в его определении.


    Получать можно точно так же как получают адрес перегруженной функции или я чего-то не вижу. Можно использовать имена __ctor, __cctor, __dtor как уже делают в Managed сообществе Было бы желание...

    ПК>И это только самая вершина айсберга...


    Это не айсберг а льдинка какая-то

    ПК>Итак, в готовом виде такой сущности как указатели на конструкторы и деструкторы в языке нет, т.к. в общем случае нет какой-то готовой функции, на которую можно было бы выдать указатель пользователю.


    ОК, указателя на контруктор нет, согласен, хотя обёрки и так генерируются и их можно было бы использовать, ну да ладно. А вот деструктор чем отличается от обычных методов?

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


    Как это нет сценариев? А универсальный type_traits? Да и не надо так говорить. Люди вон что с шаблонами делают, а выдумывали их совсем для дуругого. Так что была бы фича, а применение найдётся
    A journey of a thousand miles must begin with a single step © Lau Tsu
    Re[11]: Перегрузка операторов
    От: adontz Грузия http://adontz.wordpress.com/
    Дата: 24.05.04 20:52
    Оценка: :))
    Здравствуйте, jazzer, Вы писали:

    J> ...


    Тише! Это я, Кодт и ПК договорились друг другу оценки ставить за простые вопросы

    Censored. Нарушение п. 5. -- ПК
    A journey of a thousand miles must begin with a single step © Lau Tsu
    Re[12]: Перегрузка операторов
    От: Кодт Россия  
    Дата: 24.05.04 21:48
    Оценка: :)
    Здравствуйте, adontz, Вы писали:

    A>Тише! Это я, Кодт и ПК договорились друг другу оценки ставить за простые вопросы


    На! Получай свою заслуженную оценку
    ... << RSDN@Home 1.1.2 stable >>
    Перекуём баги на фичи!
    Re[8]: Перегрузка операторов
    От: Павел Кузнецов  
    Дата: 25.05.04 01:10
    Оценка:
    > А вот деструктор чем отличается от обычных методов?

    Тем, что в него тоже может передаваться контекст. Скажем, Visual C++ выбирает несколько другой вариант: создание набора деструкторов (scalar destructor, vector destructor...). Другая реализация вместо этого может решить передавать дополнительные аргументы. С указателями на деструкторы, вообще разговор отдельный: какой, вообще, смысл в "указателе на деструктор", если он типизирован? Деструктор у класса может быть только один, соответственно, имея указатель на класс, в "указазателях на деструктор" нужды уже никакой нет.

    > Как это нет сценариев? А универсальный type_traits? Да и не надо так говорить. Люди вон что с шаблонами делают, а выдумывали их совсем для дуругого. Так что была бы фича, а применение найдётся


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

    Что ты подразумеваешь под "универсальным type_traits"? Какое конкретное ты видишь применение "указателям на конструкторы" и "указателям на деструкторы"? Перечисли характерные особенности "указателей на конструкторы" и "указателей на деструкторы". В частности:
  • Каковы правила приведения между "указателями на конструкторы" разных типов, "указателями на деструкторы"?
  • Какова сигнатура этих "функций", в частности, возвращаемое значение.
  • Приведи примеры использования и т.п.
    Posted via RSDN NNTP Server 1.9 alpha
  • Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
    Re[9]: Перегрузка операторов
    От: adontz Грузия http://adontz.wordpress.com/
    Дата: 25.05.04 08:17
    Оценка:
    Здравствуйте, Павел Кузнецов, Вы писали:

    ПК>Тем, что в него тоже может передаваться контекст. Скажем, Visual C++ выбирает несколько другой вариант: создание набора деструкторов (scalar destructor, vector destructor...).


    Э нет. Ты меня не путай 'eh vector destructor interator' Всего лишь в цикле вызывает обычные деструкторы для каждого элемента массива. Я ещё и сам подумаю, но если я согласен про дополнительные параметры конструктора, но с деструктором у меня всё ещё сомнения. К тому же не забываем про обёртки.

    ПК>Такой подход — прямая дорога к замусориванию языка. Далеко не все "фичи" хорошо уживаются вместе (яркий пример — спецификация исключений и шаблоны).


    А как они не уживаются? Или ты про то, что сделав catch( complex<int> ) я не поймаю catch( complex<float> ) ?

    ПК>Соответственно, добавляя не слишком нужные "фичи", ты закрываешь дорогу другим, более нужным, которые ты можешь захотеть добавить позднее.


    Бывает.

    ПК>Что ты подразумеваешь под "универсальным type_traits"? Какое конкретное ты видишь применение "указателям на конструкторы" и "указателям на деструкторы"?


    Например, (моя идея-фикс) определение PODности типов.

    ПК>Перечисли характерные особенности "указателей на конструкторы" и "указателей на деструкторы". В частности:

    ПК>
  • Каковы правила приведения между "указателями на конструкторы" разных типов, "указателями на деструкторы"?

    Никаких правил. Только к void * и обратно.

    ПК>
  • Какова сигнатура этих "функций", в частности, возвращаемое значение.

    У конструкторов ссылка на объект класса, у деструкторов void.

    ПК>
  • Приведи примеры использования и т.п.

    http://www.rsdn.ru/Forum/Message.aspx?mid=608043
    Автор: adontz
    Дата: 15.04.04
    оценки сообщению прошу считать признанием полезности фичи
  • A journey of a thousand miles must begin with a single step © Lau Tsu
    Re[12]: Перегрузка операторов
    От: jazzer Россия Skype: enerjazzer
    Дата: 25.05.04 08:47
    Оценка: :))
    Здравствуйте, adontz, Вы писали:

    Censored. Нарушение п. 5 -- ПК
    jazzer (Skype: enerjazzer) Ночная тема для RSDN
    Автор: jazzer
    Дата: 26.11.09

    You will always get what you always got
      If you always do  what you always did
    Re[13]: Перегрузка операторов
    От: Red Line  
    Дата: 25.05.04 09:12
    Оценка:
    Здравствуйте, jazzer, Вы писали:

    > . . .


    Ну что успокоились? Думал написать, а Вас всё несёт и несёт...
    Вобщето переходить на личности (пусть даже через ник) есть плохой тон на форуме (впрочем как на верное и в миру).
    Думаю, господа праффессионалы, что Ваш стёб не делает Вам достоинств...

    Red Line.

    Censored. -- ПК
    Re[14]: Перегрузка операторов
    От: jazzer Россия Skype: enerjazzer
    Дата: 25.05.04 09:14
    Оценка:
    Здравствуйте, Red Line, Вы писали:

    RL>Вобщето переходить на личности (пусть даже через ник) есть плохой тон на форуме (впрочем как на верное и в миру).

    RL>Думаю, господа праффессионалы, что Ваш стёб не делает Вам достоинств...

    Действительно, господа, что-то нас занесло :(

    Red Line, приношу свои извинения

    Censored. -- ПК
    jazzer (Skype: enerjazzer) Ночная тема для RSDN
    Автор: jazzer
    Дата: 26.11.09

    You will always get what you always got
      If you always do  what you always did
    Re[14]: Перегрузка операторов
    От: adontz Грузия http://adontz.wordpress.com/
    Дата: 25.05.04 09:32
    Оценка:
    Здравствуйте, Red Line, Вы писали:

    Censored. Нарушение п. 5. -- ПК
    A journey of a thousand miles must begin with a single step © Lau Tsu
    Re[10]: Перегрузка операторов
    От: Кодт Россия  
    Дата: 25.05.04 09:59
    Оценка: +1
    Здравствуйте, adontz, Вы писали:

    A>http://www.rsdn.ru/Forum/Message.aspx?mid=608043
    Автор: adontz
    Дата: 15.04.04
    оценки сообщению прошу считать признанием полезности фичи


    Прошу считать мою оценку признанием удивительности фичи.
    "И от кота польза: он мышей ловить будет. — А у нас нет мышей! — А мы заведём!" (Простоквашино).

    Всё-таки надо различать
  • выражение placement new, которое можно записать и как new(&obj)Class(x,y,z), и как obj.__ctor(x,y,z),
  • кусок ассемблерного кода, выполняющий конструирование
    Поскольку какая подпольная работа ведётся в этом коде — зависит от реализации. Может, там есть скрытый параметр — булев флаг, управляющий конструированием виртуальной базы, а может, ещё что-то.

    Вот аналогия:
    class A
    {
    public:
      virtual void foo();
    };
    
    class B : public A
    {
    public:
      virtual void foo()
      {
        . . .
        A::foo(); // выражение статического вызова
        . . .
      }
    
      void bar()
      {
        void (A::*method)() = &A::foo; // указатель на динамический метод
        this->*method(); // то же, что и this->foo(), т.е. this->B::foo();
      }
    };




    Я не спорю, что фича __ctor/__dtor полезна тем, что упрощает синтаксис placement new, а также (как бонус) позволяет дискриминировать POD-типы.
    Но добывать где-то адрес конструктора для дела?
  • Перекуём баги на фичи!
    Re[15]: Перегрузка операторов
    От: Red Line  
    Дата: 25.05.04 10:36
    Оценка:
    Здравствуйте, adontz, Вы писали:

    A> . . .


    По поводу прочитанных книг:
    Да действительно те книги которые прочитал буквально вскользь затрагивали тему этой дискуссии.
    Сейчас по почте закаказал книгу Страуструпа, буду грызть его
    Весь смысл задаваемых мной вопросов сводится к пониманию следующего кода:
    (из книги Дейла Роджерсона "Основы технологии COM").
    Я одолел 8 глав, на девятой застрял потому-что не смог понять материал по теме "перегрузка операторов"
    Тогда и решил на Ваш форум обратиться... Впрчем вот эта глава...


    Реализация класса указателя на интерфейс

    Хотя классов smart-указателей для работы с интерфейсами СОМ и не так много, как классов строк, но число тех и
    других не сильно различается. ActiveX Template Library (ATL) содержит классы указателей на интерфейсы СОМ
    CComPtr и CComQIPtr. В библиотеке MFC имеется класс CIP для внутреннего пользования. (Он находится в
    файле AFXCOM_.H.) CIP — это самый полный вариант класса smart-указателя на интерфейс. Он делает
    практически все. Здесь я представлю свой собственный, главным образом потому, что мой код легче читается.
    Мой класс похож на классы из ATL и MFC, но не столь полон.
    ----------------------------------------------
    * Точнее, для указателя CFoo*. — Прим. перев.
    ** Функция operator-> означает не «разыменуй меня», а «используй меня для обращения к моим методам или переменным-членам» — Прим..
    перев.
    ----------------------------------------------
    Клиент вызывает члены интерфейса напрямую с помощью operator->
    Доступ к функциям-членам класса smart-указателя осуществляется с использованием нотации "точка"
    Мой класс указателя на интерфейс называется IPtr и реализован в файле PTR.H, который представлен в листинге
    Пусть длина исходного текста Вас не пугает. Кода там очень мало. Я просто вставил побольше пустых строк,
    чтобы легче было читать.


    Шаблон IPtr из PTR.H
    //
    // IPtr – Smart-указатель на интерфейс
    // Использование: IPtr<IX, &IID_IX> spIX;
    // Не используйте с IUnknown; IPtr<IUnknown, &IID_IUnknown>
    // не будет компилироваться. Вместо этого используйте IUnknownPtr.
    //
    template <class T, const IID* piid> class IPtr
    {
    public:
    // Конструкторы
    IPtr()
    {
    m_pI = NULL;
    }
    IPtr(T* lp)
    {
    m_pI = lp;
    if (m_pI != NULL)
    {
    m_pI->AddRef();
    }
    }
    IPtr(IUnknown* pI)
    {
    m_pI = NULL;
    if (pI != NULL)
    {
    pI->QueryInterface(*piid, (void **)&m_pI);
    }
    }
    // Деструктор
    ~IPtr()
    {
    Release();
    }
    // Сброс в NULL
    void Release()
    140
    {
    if (m_pI != NULL)
    {
    T* pOld = m_pI;
    m_pI = NULL;
    pOld->Release();
    }
    }
    // Преобразование
    operator T*() { return m_pI; }
    // Операции с указателем
    T& operator*() { assert(m_pI != NULL); return *m_pI; }
    T** operator&() { assert(m_pI == NULL); return &m_pI; }
    T* operator->() { assert(m_pI != NULL); return m_pI; }
    // Присваивание того же интерфейса
    T* operator=(T* pI)
    {
    if (m_pI != pI)
    {
    IUnknown* pOld = m_pI; // Сохранить старое значение
    m_pI = pI; // Присвоить новое значение
    if (m_pI != NULL)
    {
    
    m_pI->AddRef();
    }
    if (pOld != NULL)
    {
    pOld->Release(); // Освободить старый интерфейс
    }
    }
    return m_pI;
    }
    // Присваивание другого интерфейса
    T* operator=(IUnknown* pI)
    {
    IUnknown* pOld = m_pI; // Сохранить текущее значение
    m_pI == NULL ;
    // Запросить соответствующий интерфейс
    if (pI != NULL)
    {
    HRESULT hr = pI->QueryInterface(*piid, (void**)&m_pI);
    assert(SUCCEEDED(hr) && (m_pI != NULL));
    }
    if (pOld != NULL)
    {
    pOld->Release(); // Освободить старый указатель
    }
    return m_pI;
    }
    // Логические функции
    BOOL operator!() { return (m_pI == NULL) ? TRUE : FALSE; }
    // Требует компилятора, поддерживающего BOOL
    operator BOOL() const
    {
    return (m_pI != NULL) ? TRUE : FALSE;
    }
    // GUID
    const IID& iid() { return *piid; }
    private:
    // Хранимый указатель
    141
    T* m_pI;
    };


    Разборки вырезаны. -- ПК
    Подождите ...
    Wait...
    Пока на собственное сообщение не было ответов, его можно удалить.