Другое > Hard'n'Soft
Програмирование на C++
<< < (8/25) > >>
gepar:
Так, пробую дальше продвигаться по Дейтелу. Дальше у него тут перегрузка операторов, с перегрузкой ввода в поток и вывода из потока, которые были глобальными всё получилось, а вот дальше что-то я не так смотрю указываю когда операторы для  перегрузки находятся в классе. Вообще это пример из Дейтела, только у него он как всегда разбит на кучу файлов, я же вот попробовал переделать чтобы всё было в одном и что-то упустил наверное, подскажите пожалуйста что именно.

--- Код: ---# include <iostream>
# include <iomanip>
# include <cstdlib>
using namespace std;

class Array
{
    friend istream &operator>>(istream &input, Array &a);
    friend ostream &operator<<(ostream &output, const Array &a);
public:

    Array (int arraySize=10)
    {
        size=(arraySize>0 ? arraySize : 10);
        ptr=new int[size];
        for (int i=0;i<size;i++)
         ptr[i]=0;
    }

    Array (const Array &arrayToCopy)
     :size (arrayToCopy.size)
    {
        ptr=new int[size];
        for (int i=0;i<size;i++)
         ptr[i]=arrayToCopy.ptr[i];
    }

    ~Array()
    {
        delete [] ptr;
    }

    int getSize() const
    {
        return size;
    }

    const &Array operator=(const Array &right)
    {
        if (&right!=this)
        {
            if (size!=right.size)
            {
                delete [] ptr;
                size=right.size;
                ptr=new int [size];
            }
            for (int i=0;i<size;i++)
             ptr[i]=right.ptr[i];
        }
        return *this;
    }

    bool operator==(const Array &right) const
    {
        if (size!=right.size)
         return false;
        for (int i=0;i<size;i++)
         if (ptr[i]!=right.ptr[i])
          return false;
        return true;
    }

    bool operator!=(const Array &right) const
    {
        return !(*this==right);
    }

    int &Array operator [](int subscript)
    {
        if (subscript<0 || subscript >=size)
        {
            cerr<<"\nError: Subscript "<<subscript
            <<" out of range"<<endl;
            exit (1);
        }
        return ptr[subscript];
    }

    int Array operator[](int subscript) const
    {
        if (subscript<0 || subscript>=size)
        {
            cerr<<"\nError: Subscript "<<subscript
            <<" out of range"<<endl;
            exit (1);
        }
        return ptr[subscript];
    };

private:
    int size;
    int *ptr;
};

istream &operator>>(istream &input, Array &a)
{
    for (int i=0;i<a.size;i++)
     input>>a.ptr[i];
    return input;
};

ostream &operator<<(ostream &output, const Array &a)
{
    int i;
    for (i=0;i<a.size;i++)
    {
        output<<setw(12)<<a.ptr[i];
        if ((i+1)%4==0)
         output<<endl;
    }
    if (i%4!=0)
     output<<endl;

    return output;
};

int main()
{
   Array intgers1(7);
   Array integers2;
   return 0;
}

--- Конец кода ---
Сорри комментариев не писал, но они я думаю не надо сейчас. Назначение класса - сделать свой массив с блекджеком и девушками с проверкой не был ли выход за границы массива и с возможностью печати/заполнения/сравнения массива int чисел.
Ошибки компилятор выдаёт только в тех строчках где идёт объявление перегрузки операторов
const &Array operator=(const Array &right)
bool operator==(const Array &right) const
int &Array operator [](int subscript)
int Array operator[](int subscript) const
Я что-то не дописал / написал лишнее в этих строчках?
HoRRoR:
Что есть &Array? Array& пиши, чтобы ссылку объявить.
int Array - ещё лучше... Чего же тогда не int string double сразу? :D Определись уже с типом.
gepar:
HoRRoR,ну Array это и есть этот класс собственно, если убрать Array то компилятор говорит что я пытаюсь заменить оператор для непонятно чего. Инымы словами это
const &Array operator=(const Array &right)
должно позволить присваивать одному объекту класса Array значения другого объекта класса Array , при этом естественно просто будет сделана копия элементов из одного класса (того что будет справа от = (right) тому что будет слева от = ) в другой.
HoRRoR:
Ты вообще читаешь то, что я пишу? Замени &Array на Array&.
gepar:
Упростим задачу, вот код с дописанными комментариями  :)

--- Код: ---# include <iostream>
# include <iomanip>
# include <cstdlib>
using namespace std;

class Array
{
    friend istream &operator>>(istream &input, Array &a); // ввод данных в класс Array через cin
    friend ostream &operator<<(ostream &output, const Array &a);// вывод данных класса Array через cout
public:

//конструктор выделяет место под нужное колличество элементов массива
//по умолчанию на 10 элементов
    Array (int arraySize=10)
    {
        size=(arraySize>0 ? arraySize : 10);
        ptr=new int[size];
        for (int i=0;i<size;i++)
         ptr[i]=0;
    }
//конструктор копии Array (чтобы можно было сделать array1(array2))
    Array (const Array &arrayToCopy)
     :size (arrayToCopy.size)
    {
        ptr=new int[size];
        for (int i=0;i<size;i++)
         ptr[i]=arrayToCopy.ptr[i];
    }

//деструктор
    ~Array()
    {
        delete [] ptr;
    }

//возвращает размер массива
    int getSize() const
    {
        return size;
    }

//перегрузка оператора присваивания для класса Array
    Array operator=(const Array &right)
    {
        if (&right!=this)
        {
            if (size!=right.size)
            {
                delete [] ptr;
                size=right.size;
                ptr=new int [size];
            }
            for (int i=0;i<size;i++)
             ptr[i]=right.ptr[i];
        }
        return *this;
    }
//определения равны ли два массива
    bool operator==(const Array &right) const
    {
        if (size!=right.size)
         return false;
        for (int i=0;i<size;i++)
         if (ptr[i]!=right.ptr[i])
          return false;
        return true;
    }

//определение не равенства двух массивов
    bool operator!=(const Array &right) const
    {
        return !(*this==right);
    }

//возможность обращения к нужному элементу массива
//возвращает указатель на этот элемент чтобы обеспечить присваивание
//НЕ РАБОТАЕТ
    Array operator [](int subscript)
    {
        if (subscript<0 || subscript >=size)
        {
            cerr<<"\nError: Subscript "<<subscript
            <<" out of range"<<endl;
            exit (1);
        }
        return ptr[subscript];
    }

//возможность обращения к нужному элементу массива для const даных
    Array operator[](int subscript) const
    {
        if (subscript<0 || subscript>=size)
        {
            cerr<<"\nError: Subscript "<<subscript
            <<" out of range"<<endl;
            exit (1);
        }
        return ptr[subscript];
    };

private:
    int size; //размер массива
    int *ptr; //указатель на данные массива
};

istream &operator>>(istream &input, Array &a)
{
    for (int i=0;i<a.size;i++)
     input>>a.ptr[i];
    return input;
};

ostream &operator<<(ostream &output, const Array &a)
{
    int i;
    for (i=0;i<a.size;i++)
    {
        output<<setw(12)<<a.ptr[i];
        if ((i+1)%4==0)
         output<<endl;
    }
    if (i%4!=0)
     output<<endl;

    return output;
};

int main()
{
   Array integers1(7);
   Array integers2;
   cout<<integers1;
   integers1[4]=100;//не изменяет integers1[4] так как функция получает копию
   cout<<integers1;
   return 0;
}

--- Конец кода ---
Код компилируется, но беда в другом - при перегрузке операторов передаются копии. При попытке написать например
Array& operator[](int subscript) const
я получаю ошибку что у меня там мол дальше возвращается же ссылка на int данные и мол так нельзя. Пишу
int &operator[](int subscript) const
опять же таки всё компилируется но блин опять же таки нужный объект класса не модифицируется (это видно по выводу данных до и после попытки заменить 4 элемент массива в main).
 

Добавлено позже:
А, тьфу, я редактировал функцию что для const данных, тогда там просто int &operator[](int subscript) const и всё будет работать. Короче вот так тогда должно быть:

--- Код: ---# include <iostream>
# include <iomanip>
# include <cstdlib>
using namespace std;

class Array
{
    friend istream &operator>>(istream &input, Array &a); // ввод данных в класс Array через cin
    friend ostream &operator<<(ostream &output, const Array &a);// вывод данных класса Array через cout
public:

//конструктор выделяет место под нужное колличество элементов массива
//по умолчанию на 10 элементов
    Array (int arraySize=10)
    {
        size=(arraySize>0 ? arraySize : 10);
        ptr=new int[size];
        for (int i=0;i<size;i++)
         ptr[i]=0;
    }
//конструктор копии Array (чтобы можно было сделать array1(array2))
    Array (const Array &arrayToCopy)
     :size (arrayToCopy.size)
    {
        ptr=new int[size];
        for (int i=0;i<size;i++)
         ptr[i]=arrayToCopy.ptr[i];
    }

//деструктор
    ~Array()
    {
        delete [] ptr;
    }

//возвращает размер массива
    int getSize() const
    {
        return size;
    }

//перегрузка оператора присваивания для класса Array
    Array &operator=(const Array &right)
    {
        if (&right!=this)
        {
            if (size!=right.size)
            {
                delete [] ptr;
                size=right.size;
                ptr=new int [size];
            }
            for (int i=0;i<size;i++)
             ptr[i]=right.ptr[i];
        }
        return *this;
    }
//определения равны ли два массива
    bool operator==(const Array &right) const
    {
        if (size!=right.size)
         return false;
        for (int i=0;i<size;i++)
         if (ptr[i]!=right.ptr[i])
          return false;
        return true;
    }

//определение не равенства двух массивов
    bool operator!=(const Array &right) const
    {
        return !(*this==right);
    }

//возможность обращения к нужному элементу массива
//возвращает указатель на этот элемент чтобы обеспечить присваивание
    int &operator [](int subscript)
    {
        if (subscript<0 || subscript >=size)
        {
            cerr<<"\nError: Subscript "<<subscript
            <<" out of range"<<endl;
            exit (1);
        }
        return ptr[subscript];
    }

//возможность обращения к нужному элементу массива для const даных
    int operator[](int subscript) const
    {
        if (subscript<0 || subscript>=size)
        {
            cerr<<"\nError: Subscript "<<subscript
            <<" out of range"<<endl;
            exit (1);
        }
        return ptr[subscript];
    };

private:
    int size; //размер массива
    int *ptr; //указатель на данные массива
};

istream &operator>>(istream &input, Array &a)
{
    for (int i=0;i<a.size;i++)
     input>>a.ptr[i];
    return input;
};

ostream &operator<<(ostream &output, const Array &a)
{
    int i;
    for (i=0;i<a.size;i++)
    {
        output<<setw(12)<<a.ptr[i];
        if ((i+1)%4==0)
         output<<endl;
    }
    if (i%4!=0)
     output<<endl;

    return output;
};

int main()
{
   Array integers1(7);
   Array integers2;
   cout<<integers1;
   integers1[4]=100;//не изменяет integers1[4] так как функция получает копию
   cout<<integers1;
   return 0;
}

--- Конец кода ---
Сейчас только в main протестирую всё ли работает теперь как положено.

Добавлено позже:
HoRRoR,читаю, просто этот совет твой не для всех функций помог, ну да я уже "добил" этот класс и теперь вроде перегрузка операторов стала понятнее.

Добавлено позже:
Небольшой вопрос на тему правильно ли я понял:
если у меня идёт перегрузка оператора "внутри" класса и она возвращает что-то (в данном случае ссылку на данные типа int) то я пишу так:
    int operator[](int subscript) const
    {
        if (subscript<0 || subscript>=size)
        {
            cerr<<"\nError: Subscript "<<subscript
            <<" out of range"<<endl;
            exit (1);
        }
        return ptr[subscript];
    };
А если ничего не возвращает или возвращает указатель *this то я вместо того чтобы написать void должен писать имя класса, так?
HoRRoR:
Ты в любом случае пишешь возвращаемый тип. *this - объект типа данного класса, т.е. да, ты должен писать имя класса в качестве типа возвращаемого объекта. Если ничего не возвращает (правда зачем тебе такой оператор?) - то void, естественно.


--- Цитата ---(в данном случае ссылку на данные типа int)
--- Конец цитаты ---
У тебя тут не ссылка, а просто int.
gepar:
HoRRoR, ну как зачем?  :) Ну вот набросок маленький опять на ту же самую тему (создание своего массива), фантазии что-то у меня вчера не хватило по поводу темы очередной программы-примера  :) Здесь меньше проверок, но дело не в них, посмотри пожалуйста на перегрузку оператора присваивания, там я уже в комментарии расписал что получается если указать void (несмотря на то что класс ничего не возвращает) поэтому я оставил как тип название класса (Test).


--- Код: ---# include <iostream>
# include <iomanip>
using namespace std;

class Test
{
    friend ostream &operator<<( ostream &output, Test &a);//перегрузка глобального оператора вывода
public:
    Test(int a=10)//конструктор для нового "массива"
    {
        size=a;
        ptr=new int [size];
        for (int i=0;i<size;i++)
         ptr[i]=0;
    }

//перегрузка оператора =
//по сути ведь нужен void так как вызов же будет
//что-то типа xyz.operator=(abc)
//+ ничего возвращать ведь не надо, но
//если написать void то компилятор будет ругаться
//на строку 24(где открывается { со сл. ошибкой:
// 24|error: cannot declare reference to `void'|

    Test &operator=(Test b)
    {
        for (int i=0;i<size;i++)
         this->ptr[i]=b.ptr[i];
    }


    int &operator[](int x)// перегрузка [] для обращения к нужному элементу "массива"
    {
        return this->ptr[x];
    }

private:
    int size;// размер массива
    int *ptr; // указатель на него (массив)
};

ostream &operator<<( ostream &output, Test &a)
{
    for (int i=0;i<a.size;i++)
     output<<a.ptr[i]<<" ";
    output<<'\n';
}

int main()
{
    Test abc(5);// новый "массив" размером 5
    Test xyz(5);
    cout<<abc;//вывод abc
    abc[3]=100;//изменяем 3ий элемент на 100
    xyz=abc;//присваиваем xyz значения abc
    cout<<xyz;//проверяем было ли присваивание
    cout<<abc;//проверяем равен ли 100 3ий элемент
    return 0;
}


--- Конец кода ---
HoRRoR:
Ну я думал ты это про [] говоришь.
А ошибка у тебя потому что нехрен ссылку типа void делать. Вот читаешь ты учебник, а толку, если ляпы у тебя детские? Убери амперсант, тогда сможешь void написать. Вчитывался бы хотя бы в текст ошибок...
gepar:

--- Цитата: HoRRoR ---А ошибка у тебя потому что нехрен ссылку типа void делать.
--- Конец цитаты ---
:) Так я же думал что & относиться к operator=, а не к void. Всегда ведь & относиться к тому что за ним написано, а не перед.
HoRRoR:
Скажи мне, какой тогда, на твой взгляд, он нёс функционал? Ты всегда пишешь операторы с неизвестным тебе функционалом?
int* - тип, звёздочка относится к инту. int& - то же самое. int *abc - объявление переменной, звёздочка относится к abc.
gepar:
HoRRoR,ну я считал что для перегрузки операции нужно чтобы она производилась по значению (те потому и &). Хотя я наверное мрачно объяснил что я хотел написать, ну да ладно, упустим это.

--- Цитата: HoRRoR ---int* - тип, звёздочка относится к инту. int& - то же самое.
--- Конец цитаты ---
Я пока что не знаю что это такое и что так вообще можно  :) Ну и вообще раздел по перегрузке операторов Дейтела я ещё не дочитал, то была проба пера.

Добавлено позже:
Встречный вопрос: а как же задать тип int*, компилятор же всегда думает что это указатель и что * относится к имени переменной следующей после int (например int* abc).
Mr2:

--- Цитата: gepar от 13 Февраль 2011, 16:53:38 ---Вопрос номер n+1: А как-то можно ограничить ввод? Только не по количеству символов, а чтобы когда я ожидаю что будет введено число то символы не вводились и наоборот? В многих приложениях я встречал что когда пытаешься ввести в поле для цифр символы то ввод не происходит, правда эти приложения не являлись консольными так что не знаю можно ли сделать что-то подобное здесь.

--- Конец цитаты ---

--- Код: ---//input check 12.03.2011

#include <iostream>

using namespace std;

int main(){
 int input = 0;
 for(int i = 0; i < 10;++i){
   cout << endl;
   cout << "      Enter number: ";
   cin >> input;
   cout << endl;
   if(cin.fail()){ //если состояние входного потока ошибочное.
     cin.clear(); //сбросить поток...
     string garbage;
     getline(cin, garbage); //... и пропустить всю строку.
     cout << "  This is not a number!!! " <<endl;
     }    
   else
   cout << "       You enter: " << input <<endl;
  }  
 system("pause");
}

--- Конец кода ---
Вот нашёл сегодня. :)
gepar:
Mr2,во, круто! Попробую сегодня что-то написать маленькое с использованием этой проверки cin.fail.
HoRRoR:

--- Цитата ---Встречный вопрос: а как же задать тип int*, компилятор же всегда думает что это указатель и что * относится к имени переменной следующей после int (например int* abc).
--- Конец цитаты ---
What? int* или int *a или int *a, *b - чем не ответ на твой вопрос? На крайний случай - typedef или define.


--- Цитата ---Вот нашёл сегодня.
--- Конец цитаты ---
Нажимаю, к примеру, f - вводится f. В чём соль, если речь шла об ограничении ввода, а не о проверке? Т.е. жму f - f не вводится и в консоли не появляется, жму 4 - 4 вводится.
gepar:
HoRRoR,ну да это не совсем то чего хотелось изначально, но это хоть что-то. Да в этом случае вводиться всё равно будет всё подряд, но будет хотя-бы проверка что данные соответствуют типу и "не совместимые" данные не будут сохраняться в переменную  :)
Mr2:

--- Цитата: gepar от 12 Март 2011, 14:46:06 ---HoRRoR,ну да это не совсем то чего хотелось изначально, но это хоть что-то. Да в этом случае вводиться всё равно будет всё подряд, но будет хотя-бы проверка что данные соответствуют типу и "не совместимые" данные не будут сохраняться в переменную  :)

--- Конец цитаты ---
Молодец! :) Правильно!
gepar:
Работает слегка непонятно, например я ввожу 121212abc23423
тоесть в  input у меня должны быть неправильные данные (они ведь подряд записаны). Но при этом я сначала почему-то получаю выполнение того что по else (программа пишет что я ввёл 121212 (всё что до abc)) и потом тут же выполняется то что в if(cin.fail()) и пишет мол были введены не числа. Почему так?
Кстати проверка идёт потока ,а не содержимого int переменной в которую был ввод из потока. Это что значит что поток "помнит" последние вводимые данные или я тут тоже что-то не так понял? Подскажите пожалуйста.

Добавлено позже:
Нашёл очередной способ вывода русского текста, этот совсем короткий - всего одна строчка:
setlocale(LC_ALL, "Russian");
Mr2:

--- Цитата: gepar от 13 Март 2011, 03:02:55 ---Работает слегка непонятно, например я ввожу 121212abc23423
тоесть в  input у меня должны быть неправильные данные (они ведь подряд записаны). Но при этом я сначала почему-то получаю выполнение того что по else (программа пишет что я ввёл 121212 (всё что до abc)) и потом тут же выполняется то что в if(cin.fail()) и пишет мол были введены не числа. Почему так?
--- Конец цитаты ---

 В подробности потоков пока не вникал. Видимо поток действительно всё помнит.
 Не с проста нужно пропускать строку.(getline(cin, garbage); //... и пропустить всю строку.)
 Но странно что продолжается  вывод игнорируя ввод пользователя.(cin >> input; :?)

--- Цитата: gepar от 13 Март 2011, 03:02:55 ---Кстати проверка идёт потока ,а не содержимого int переменной в которую был ввод из потока. Это что значит что поток "помнит" последние вводимые данные или я тут тоже что-то не так понял? Подскажите пожалуйста.

--- Конец цитаты ---
Тут главное что гарантируется что в int будет введено число а не символ. А уж какие значения допустимы решает сам программист.

Подправил вывод. :)

--- Код: ---//input check 13.03.2011

#include <iostream>

using namespace std;

int main(){
 int input = 0;
 for(int i = 0; i < 10;++i){
   cout << endl;
   cout << "      Enter number: ";
   cin >> input;
   cout << endl;
   if(cin.fail()){ //если состояние входного потока ошибочное.
     cin.clear(); //сбросить поток...
     cin.ignore();
     //string garbage;
     //getline(cin, garbage); //... и пропустить всю строку.
     cout << "  This is not a number!!! " <<endl;
     }   
   else
   cout << "       You enter: " << input <<endl;
   string garbage;
   getline(cin, garbage); //... и пропустить всю строку.
  }   
 system("pause");
}

--- Конец кода ---
gepar:
Пытаюсь тут сделать свой двухмерный массив с обращением к элементам как в паскале (1,2) вместо [1] [2].
Да только чего-то мой конструктор копии рушит работу всей программы, притом даже если я его не использую, а только он присутствует в коде то тут же отваливается возможность проверки на равенство двух объектов классов o_0

--- Код: ---# include <iostream>
# include <iomanip>
using namespace std;

class Array
{
public:
    //конструктор по умолчанию
    Array(int a, int b)
    {
        row=(a>0) ? a:1;
        column=(b>0)? b:1;
        ptr= new int [row*column+1];
        for (int i=0;i<row*column+1;i++)
         ptr[i]=0;
    }

    //конструктор копии который не работает
    Array (const Array &abc)
    {
        if (*this!=abc);
        {
            if (row!=abc.row || column!=abc.column)
            {
                delete []ptr;
                row=abc.row;
                column=abc.column;
                ptr=new int[row*column+1];
            }
            for (int i=0;i<row*column+1;i++)
             ptr[i]=abc.ptr[i];
        }
    }

    //возможность обращения к нужному элементу массива
    int &operator()(int a, int b)
    {
        if ((a>0) && (a<=row) &&(b>0) && (b<=column))
         if (a==1)
          return ptr[a+b];
         else
          return ptr[(a-1)*column+b];
        else
         exit(100500);
    }

    //возможность обращения к нужному элементу массива для const объекта класса
    int &operator()(int a, int b) const
    {
        if ((a>0) && (a<=row) &&(b>0) && (b<=column))
         if (a==1)
          return ptr[a+b];
         else
          return ptr[(a-1)*column+b];
        else
         exit(100500);
    }

    //проверка на равенство
    bool operator==(Array test)
    {
        if ((row!=test.row) || (column!=test.column))
         return false;
        for (int j=0;j<row*column+1;j++)
         if (ptr[j]!=test.ptr[j])
          return false;
        return true;
    }

    //проверка на неравенство
    bool operator !=(Array test)
    {
        return !(*this==test);

    }



private:
    int row; //колличество строк
    int column; //колличество столбцов
    int *ptr; //указатель на массив с элементами int
};


int main()
{
    Array a(5,5);
    Array b(5,5);
    cout<<boolalpha<<(a!=b);//без попытки их сравнить программа
                            //в процессе работы ошибку возвращать не будет
    return 0;
}


--- Конец кода ---


Добавлено позже:
Тааак, в общем-то я напортачил с проверкой вначале не делаем ли мы самоприсваивание, уже понятно, осталось это исправить  :)

Добавлено позже:
да только чего-то не получается, как бы её грамотно устроить?
Mr2:

--- Цитата: gepar от 16 Март 2011, 23:41:57 ---Пытаюсь тут сделать свой двухмерный массив с обращением к элементам как в паскале (1,2) вместо [1] [2].

--- Конец цитаты ---
Фигнёй ты страдаешь. :)
 Не вникал в твои усовершенствования матрицы, но так делать незя. :D
if (*this!=abc);
Навигация
Главная страница сообщений
Следующая страница
Предыдущая страница

Перейти к полной версии