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


Автор: S3_ 7.9.2009, 20:01
Здравствуйте. Есть такая проблема. Класс complex с переменными real и imag, при перегрузкe friend double& operator= (const complex& c) что бы можно было присвоить типу Double свой тип Complex, вызывает ошибку operator= must be a non-static member. Вопрос заключается в том, как перегрузить знак "=" что бы Complex можно было присвоить какому либо типу (например тот же Double). Искал в интернете, толком ничего не нашел  smile . Вычитал что 
Цитата

No operator= can be declared as a nonmember function
, тоесть она должна быть функцией-членом класса? Как тогда сделать присвоение/преобразование типа???

Код

class complex
{
public:
    complex (double r, double i) { real = r; imag = i; }
    complex (complex& a) { real = a.real; imag = a.imag; }

//тут другие перегруженные операторы типа +, -, *, <<, >>, унарный минус и др.

    friend double& operator= (double& d, const complex& c);    //здесь error "operator= must be a non-static member"
//при выполнении "=" должно быть присвоение d=c.real
private:
    double real, imag;
};

double& operator= (double& d,const complex& c)
 {
    d=c.real;
    return d;
 }


Заранее спасибо за помощ  smile 

Автор: zim22 7.9.2009, 20:45
operator= не может быть friend.
он должен быть определён внутри класса.
***
можно определить свой оператор преобразования в тип double.
Код

operator double() {
  return 22.33;
}

Автор: ller 7.9.2009, 21:04
Из этого все равно ничего не выйдет. Компилятор в выражении d = c всегда будет пытаться преобразовать класс complex в double.
Причем средствани объекта double... А он ничего не подозревает о существовании complex 

Автор: zim22 7.9.2009, 21:10
Цитата(ller @  7.9.2009,  21:04 Найти цитируемый пост)
Из этого все равно ничего не выйдет. Компилятор в выражении d = c всегда будет пытаться преобразовать класс complex в double.

 smile 
Код

class complex
{
public:
    complex (double r, double i) { real = r; imag = i; }
    complex (complex& a) { real = a.real; imag = a.imag; }

    operator double() {
      return 22.33;
    }
private:
    double real, imag;
};

int main() {
  complex c(10, 20);
  double r = c;
}

Автор: ller 7.9.2009, 21:11
Обратное же работает

Код


complex& operator = (const double &d);  


complex& complex::operator = (const double &d)
 {
    re = d;
    im = 0;
    return *this;
 }


Автор: Anikmar 7.9.2009, 21:15
Цитата(zim22 @  7.9.2009,  21:10 Найти цитируемый пост)
return 22.33;

 smile 

 smile 

Автор: ller 7.9.2009, 21:16
Хотя да. Оператор преобразования типа работает....  smile

Добавлено через 45 секунд
Код

    operator double() {
      return real;
    }


Автор: S3_ 8.9.2009, 00:43
Ура, работает этот оператор преобразования типа. Спасибо, я о нем думал как раз, вот только не знал как правильно реализовать smile Теперь double присваивается комплексное число  smile 

Спасибо за помощ  smile 

Автор: Леопольд 8.9.2009, 18:07
Цитата(S3_ @  8.9.2009,  00:43 Найти цитируемый пост)
Ура, работает этот оператор преобразования типа.

Но не стоит переусердствовать с "пользовательскими" преобразаованиями. Так же надо помнить, что больше двух "пользовательских" преобразований за раз не допустимо. 

P.S.
Конструкторы, с одним аргументом, тоже "пользовательское" преобразование.

Автор: IKM2007 8.9.2009, 18:58
Цитата(Леопольд @  8.9.2009,  18:07 Найти цитируемый пост)
Но не стоит переусердствовать с "пользовательскими" преобразаованиями.

Да и вообще не рекомендуется, так-как может привести к затруднениям, о которых вы и не можете подозревать. Например, для класса Complex вы должны  были обьявить оператор <<, чтобы напечатать число так: "(a, b)", но забыли определить оператор <<. Однако после компиляции увидели, что следующий код "работает":

Код

Complex x(1, 2);
std::cout<<x<<"\n";


На самом деле компилятор не находит обьявленный оператор << для аргумента типа Complex, и пытается найти последовательность операторов неявного преобразования, чтобы вызвать оператор <<, и находит приведение к типу  double, затем уже вызывает operator << для double. То есть мы вызвали не ту функцию, которую хотели бы вызвать, а это не хорошо. smile 

Автор: Леопольд 8.9.2009, 19:16
Цитата(Леопольд @  8.9.2009,  18:07 Найти цитируемый пост)
Так же надо помнить, что больше двух "пользовательских" преобразований за раз не допустимо. 

Больше одного, а не двух!

Добавлено через 46 секунд
Цитата(Леопольд @  8.9.2009,  18:07 Найти цитируемый пост)
Конструкторы, с одним аргументом, тоже "пользовательское" преобразование.

Если конечно он не объявлен как explicit

Автор: Леопольд 8.9.2009, 19:41
Цитата(IKM2007 @  8.9.2009,  18:58 Найти цитируемый пост)
Да и вообще не рекомендуется

Я бы так не сказал, всё можно пользовать, только надо подходить правильно... Иногда это ОЧЕНЬ удобно, и вполне безопасно.
Код

#include <cstddef>
#include <iostream>

class BitSet{
    class Proxy{
        unsigned char& ref;
        const unsigned char shift;
    public:
        Proxy(unsigned char& ref_, const unsigned char shift_): ref(ref_), shift(shift_) {}

        operator const bool() const{
            return (ref & (1 << shift)) != 0;
        }
        Proxy& operator= (bool bit){
            if(bit)
                ref |= 1 << shift;
            else
                ref &= ~(1 << shift);
            return *this;
        }
        Proxy& operator= (const Proxy& rArg){
            *this = static_cast<const bool>(rArg);
            return *this;
        }
    };

    unsigned char byte;

public:

    BitSet(unsigned char byte_): byte(byte_) {}

    Proxy operator[](std::size_t i){
        return Proxy(byte, i);
    }
};

inline std::ostream& operator<<(std::ostream& out, const BitSet& bits){
    for(std::size_t i=7; i<8; --i)
        out<<const_cast<BitSet&>(bits)[i];
    return out;
}

int main()
{
    BitSet bits(0);
    bits[0] = 1;
    std::cout << "bits = "<<bits<<std::endl;
    bits[1] = bits[0];
    std::cout << "bits = "<<bits<<std::endl;
    return 0;
}


Автор: IKM2007 8.9.2009, 19:43
Цитата(Леопольд @  8.9.2009,  18:07 Найти цитируемый пост)
 Так же надо помнить, что больше двух "пользовательских" преобразований за раз не допустимо. 


Цитата(Леопольд @  8.9.2009,  19:16 Найти цитируемый пост)
Больше одного, а не двух!


Цитата(Леопольд @  8.9.2009,  18:07 Найти цитируемый пост)
Конструкторы, с одним аргументом, тоже "пользовательское" преобразование.


Цитата(Леопольд @  8.9.2009,  19:16 Найти цитируемый пост)
Если конечно он не объявлен как explicit

Леопольд, Вы что спорите с самим собой?

Автор: Леопольд 8.9.2009, 19:44
Код

bits = 00000001
bits = 00000011


Добавлено через 2 минуты и 6 секунд
Цитата(IKM2007 @  8.9.2009,  19:43 Найти цитируемый пост)
Леопольд, Вы что спорите с самим собой?

В споре рождается истина smile
Я просто поправил сам себя. Что бы не вводить никого в заблуждение.

Автор: IKM2007 8.9.2009, 19:49
Цитата(Леопольд @  8.9.2009,  19:41 Найти цитируемый пост)
Я бы так не сказал, всё можно пользовать, только надо подходить правильно... Иногда это ОЧЕНЬ удобно, и вполне безопасно.

Да, но врядли автор топика знает про proxy-классы, если задает такой вопрос. smile Можно вместо этого просто написать соответствущую функцию:

Код

class Complex
{
public:
...
double toDouble()const;
};

int main()
{
...
Complex a(1, 2);
std::cout<<a.toDouble()<<"\n";
}

Автор: bsa 8.9.2009, 23:22
Если не ошибаюсь, простое преобразование complex -> double в принципе невозможно. Так как действительное число - частный случай комплексного (мнимая часть равна нулю). Введение подобного преобразования ведет к увеличению вероятности ошибки при программировании. По хорошему, программист (пользователь класса) должен себе полностью отдавать отчет, когда делает такое преобразование. Поэтому подобные преобразования наоборот усложняют (чтобы было видно, что именно делается в данной строке)!

Автор: S3_ 9.9.2009, 18:49
Цитата(IKM2007 @  8.9.2009,  18:58 Найти цитируемый пост)
Например, для класса Complex вы должны  были обьявить оператор <<, чтобы напечатать число так: "(a, b)", но забыли определить оператор <<.


Я их перегрузил (в самом первом моем сообщении строчка кода номер "7")

Цитата(IKM2007 @  8.9.2009,  19:49 Найти цитируемый пост)
Да, но врядли автор топика знает про proxy-классы, если задает такой вопрос.

 Угу, не знаю   smile 

Цитата(bsa @  8.9.2009,  23:22 Найти цитируемый пост)
Если не ошибаюсь, простое преобразование complex -> double в принципе невозможно. Так как действительное число - частный случай комплексного (мнимая часть равна нулю).


Да, я писал этот класс, и возникла вот такой вот вопрос, как его присвоить, например, double... Так что присваивать double только значение real неправильно. smile 

Автор: bsa 9.9.2009, 20:03
S3_, я с точки зрения математики высказался: вещественный числа - это подобласть пространства комплексных чисел. Т.е. комплексное число содержит больше информации, чем действительное. Даже компилятор, когда ты присваиваешь переменную более точного типа менее точному (float = double или char = int, например), всегда выдасть предупреждение. А ты делаешь конвертацию. Повторяю, с точки зрения правильного проектирования класса, это делать нельзя.

Автор: Леопольд 9.9.2009, 20:14
Цитата(S3_ @  9.9.2009,  18:49 Найти цитируемый пост)
Да, но врядли автор топика знает про proxy-классы, если задает такой вопрос.

 Угу, не знаю

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

Вообще, надо пытаться программировать так, чтобы можно было держать в голове как можно меньше деталей работы отдельных частей программы и не боятся при этом совершить обшибку.

Автор: IKM2007 10.9.2009, 14:38
Цитата(S3_ @  9.9.2009,  18:49 Найти цитируемый пост)
Я их перегрузил (в самом первом моем сообщении строчка кода номер "7")

Я не говорил именно о твоем примере.

Автор: choiming 11.9.2009, 12:09
да конечно очень нужная вещь

Автор: S3_ 12.9.2009, 13:05
Цитата(bsa @  9.9.2009,  20:03 Найти цитируемый пост)
S3_, я с точки зрения математики высказался: вещественный числа - это подобласть пространства комплексных чисел. Т.е. комплексное число содержит больше информации, чем действительное. Даже компилятор, когда ты присваиваешь переменную более точного типа менее точному (float = double или char = int, например), всегда выдасть предупреждение. А ты делаешь конвертацию. Повторяю, с точки зрения правильного проектирования класса, это делать нельзя. 


Я это знаю и придерживаюсь этого же мнения, ты наверное меня на так понял smile Конечно нельзя так делать как я   smile 

 smile 


Цитата(IKM2007 @  10.9.2009,  14:38 Найти цитируемый пост)
Цитата(S3_ @  9.9.2009,  18:49 Найти цитируемый пост)
Я их перегрузил (в самом первом моем сообщении строчка кода номер "7")

Я не говорил именно о твоем примере. 


Ой, сорри, не допонял  smile 


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