Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Перегрузка оператора <<

512
22 ноября 2006 года
bnm
124 / / 17.10.2004
Помогите написать класс метод которого перегружает << так чтобы объект этого класса можно было вывести как cout<<Object;
Пример класса:
class string
{
char *data;
public:
string(char *str) {strcpy(data, str);} // Конструктор
<type> operator << (<type>){???} // Метод перегрузки
}Object;
3
22 ноября 2006 года
Green
4.8K / / 20.01.2000
пользуемся поиском по форуму:
http://forum.codenet.ru/showthread.php?t=31233
http://forum.codenet.ru/showthread.php?t=30557
5.9K
24 ноября 2006 года
Zushenskiy
161 / / 29.06.2006
Код:
class name_class
{
int iFirstVar;
int iSecondVar;
public:
friend ostream& operator<<(ostream&, name_class);
};

friend ostream& operator<<(ostream& stream, name_class obj)
{
stream<<obj.iFirstVar<<" "<<obj.iSecondVar<<endl;
return stream;
}
можно так а можно и без друга тогда доступ к закрытым и защищенным членам не будешь иметь.
355
25 ноября 2006 года
&lt;SCORP&gt;
786 / / 21.10.2006
Код:
#include "stdafx.h"
#include <iostream>

using namespace std;

class MyClass
{
public:
    int i;
    operator char* ()
    {
        return "my string";
    }
};


int _tmain(int argc, _TCHAR* argv[])
{
    MyClass c;
    cout << c << endl;
    return 0;
}


помоему, это более правильно и в любом случае более красиво. просто доопределяем оператор приведения к строке ;)

в строке cout << MyObject оператор << вызывается не у MyObject, а у cout!!!!!!! поэтому перегружать надо не его!
3
25 ноября 2006 года
Green
4.8K / / 20.01.2000
Ничего правильного нет, ничего красивого не вижу.
Кроме того, что этот код потенциально опасен, он ещё и не делает того, что надо. Логично предположить, что даже при таком простейшем классе MyClass, пользователь захочет увидеть содержимое полей класса интерпретируемое специально для вывода, т.е. в даном случае хотя бы значение i, а не строку "my string".
355
25 ноября 2006 года
&lt;SCORP&gt;
786 / / 21.10.2006
ну, вместо my string там может быть что угодно -- сам понимаешь! там можно и i отдавать, и любые другие члены класса и чёрт знает что ещё :)
а по поводу потенциальной опасности можно поподробнее, пожалуйста?
3
25 ноября 2006 года
Green
4.8K / / 20.01.2000
[QUOTE=<SCORP>;155913]ну, вместо my string там может быть что угодно -- сам понимаешь! там можно и i отдавать, и любые другие члены класса и чёрт знает что ещё :)
[/QUOTE]
Представь пример хотя бы с выводом i, и тогда вся "красота" видна и будет.
Кроме того, оператор приведения типов используется в одних случаях, а вот переопределенные оператор << совершенно в других и эти случаи концептуально разные. Не стоит мешать все в одну кучу.
[QUOTE=<SCORP>;155913]
а по поводу потенциальной опасности можно поподробнее, пожалуйста?[/QUOTE]
Ты возвращаешь char* на строковый литерал, сл-но можно спокойно попытаться писать в эту область:
 
Код:
int main()
{
    MyClass c;

    char* ch = c;
    ch[0] = '\0';

    cout << c << endl;
    return 0;
}
355
25 ноября 2006 года
&lt;SCORP&gt;
786 / / 21.10.2006
и пиши наздоровье, только если ты не собираешься позвращать указатели на члены класса. или теперь вообще не возвращать указатели из функций?????
ну по поводу использования оператора << спорить не буду -- никогда им пользовался, собссно :)
3
25 ноября 2006 года
Green
4.8K / / 20.01.2000
[QUOTE=<SCORP>;155933]и пиши наздоровье, только если ты не собираешься позвращать указатели на члены класса. или теперь вообще не возвращать указатели из функций?????
[/QUOTE]
В подобных случаях следует возвращать константные указатели.
38K
26 апреля 2008 года
sorrelcat
6 / / 17.04.2008
Вопрос следующий. Есть класс строки, для которого перегружен оператор <<, строка является типом члена класса "Элемент двусвязного списка" (для которого << не перегружен), а этот класс, в свою очередь, является типом для элементов класс "Двусвязный список". Не получается перегрузить оператор << как дружественную функцию (второй раз с другим списком параметров) для класса "Двусвязный список". Для "полноты впечатлений" привожу весь код:
[HTML]#include <iostream>
#include <string>
using namespace std;

#define maxl 255 //максимальная длина строки
char* glob_char;

class str //класс строки
{
public://закрытая секция
int length; //длина строки
char *p; //указатель на массив символов для строки
public: //открытая секция класса
str();
str(const char *); //строка задается датой
str(int); //строка задается длиной
~str(); //деструктор очищает динамически выделенную память
str(const str &); //конструктор копий
void echo_data(); //функция выводит в стандартный поток длину и содержимое строки
str operator=(str); //перегруженный оператор присваивания
friend ostream &operator<<(ostream &, str); //перегруженный дружественный оператор вывода в стандартный поток
};

ostream &operator<<(ostream &stream, str t)
{
for(int i=0; i<t.length; ++i) stream<<t.p;
}

str::str()
{
cout << "Default str constructor without parameters" << endl;
length=maxl+1;
p=new char[length];
for (int j=0;j<length-1; ++j) p[j]='_';
p[length-1]='\0';
}

str::str(const char *t)
{
cout << "Constructor str with char* parameter" << endl;
int a=strlen(t);
if(a>maxl) {cout << "Error! Too long string" << endl; return;}
length=a+1;
p=new char[length];
for (int i=0;i<a; ++i) p=t;
p[length-1]='\0';
}

str::str(int i)
{
cout << "Constructor str with default int parameter" << endl;
if(i>maxl) {cout << "Error! Too long string" << endl; return;}
p=new char[i+1];
length=i+1;
for (int j=0;j<length-1; ++j) p[j]='a';
p[length-1]='\0';
}

str::str(const str &t)
{
cout << "Str copy constructor" << endl;
length=t.length;
p=new char [length];
for (int i=0;i<length; ++i) p=t.p;
}

str::~str()
{
cout << "Destructor str for " << endl;
echo_data();
delete [] p;
}

void str::echo_data()
{
cout << length-1 << "\t";
for (int i=0; i<length; ++i) cout << p;
cout << endl;
}

str str::operator =(str t)
{
cout << "Str operator =" << endl;
if(t.p[t.length-1]!='\0') {t.length++; t.p[length-1]='\0';}
delete [] p;
p=new char[t.length];
length=t.length;
for(int i=0;i<length-1;++i) p=t.p;
p[length-1]='\0';
return *this;
}

class delem //класс элемента двусвязного списка
{
public:
str data; //строка данных списка
delem *next; //указатель на следующий элемент
delem *prev; //указатель на предыдущий элемент
delem(); //конструктор по умолчанию
//delem(delem, str); //конструктор с параметром
delem(const delem &); //конструктор копий
~delem(); //деструктор
delem operator=(delem); //перегруженный оператор присваивания, копирует данные и связи
};

delem::delem() //конструктор по умолчанию создает элемент список из 1 пустой строки
{
cout << "Delem default constructor" << endl;
data="\0";
next=NULL;
prev=NULL;
}

/*delem::delem(delem t, str k="\0") //конструктор с параметром по умолчанию
{ //создает элемент списка после указанного
cout << "Delem constructor with default parameter" << endl;
*prev=t;
next=t.next;
data=k; //и присваивает строке значение; если оно не заданное явно, то присваивается значение по умолчанию
}*/

delem::~delem()
{
cout << "Delem destructor" << endl;
}

delem::delem(const delem &t) //конструктор копий копирует строку элемента в новый элемент с нулевыми связями
{
cout << "Delem copy constructor" << endl;
next=NULL;
prev=NULL;
data=t.data;

}

delem delem::operator =(delem t)
{
cout << "Delem operator =" << endl;
next=t.next;
prev=t.prev;
data=t.data;
return *this;
}

class dlist //собственно класс двусвязного списка
{
private: //закрытая секция
delem *head; //указатель на голову списка
delem *tail; //указатель на хвост списка
int count; //количество элементов списка
public: //открытая секция
dlist(); //конструктор по умолчанию
dlist(const dlist &); //конструктор копирования
dlist(int, str); //конструктор с параметром
~dlist(); //деструктор удаляет все элементы списка
void to_tail(str); //добавление строки в хвост списка
void del(int); //удаление элемента по номеру
dlist operator+(const dlist &); //вставка элементов одного списка в хвост другого
dlist operator+(const delem); //вставка строки из элемента в конец списка
delem operator[](int); //перегрузка оператора индексирования, возвращает элемент по номеру
dlist operator-(int); //удаление элемента по номеру
bool operator==(dlist); //сравнивает длины списков - возвращает истину, если длины равны
bool operator>(dlist); //сравнивает длины списков, возвращает истину, если левый операнд длинее правого
delem get_head(); //возвращает указатель на голову списка
friend ostream& operator<<(ostream&, dlist);

};

delem dlist::get_head()
{
return *head;
}

dlist::dlist() //создает пустой список
{
cout << "Dlist default constructor" << endl;
head=0;
tail=0;
count=0;
}

dlist::dlist(const dlist &t) //конструктор копий
{
cout << "Dlist copy constructor" << endl;
head = tail = 0; //обнуляет указатели головы и хвоста списка
count = 0; //и количество его элементов
delem* temp = t.head; //создает новый элемент из головы передаваемого списка
while(temp != 0) //и копирует элементы и связи переданного списка, пока не дойдет до хвоста
//(где укаатель на следующий элемент нулевой)
{
to_tail(temp->data);
temp = temp->next;
}
}

dlist::dlist(int n, str k="\0") //создает список из n элементов, по умолчанию - пустых строк
{
cout << "Dlist constructor with parameter" << endl;
for(int i=0;i<n;++i)
to_tail(k);
}

dlist::~dlist()
{
while(count != 0) //удаляем первый элемент, пока элементы есть в списке
del(1);
cout << "Destroyed by dlist destructor" << endl;
}

void dlist::to_tail(str t)
{
delem * temp = new delem; //выделяем память для нового элемента списка
temp->next = 0; //следующего элемента для него не будет
temp->data = t; //данные внесем из строки-параметра
temp->prev = tail; //а предыдущим - хвостовой (бывший)
if(tail != 0) //если хвост списка существует,
tail->next = temp; //то следующим элементом для хвостового будет вставляемый
if(count == 0) //если список пустой, то при добавлении в него одного элемента
head = tail = temp; //и головой, и хвостом для этого списка будет вставленный элемент
else //в противном случае вставленный элемент станет хвостовым
tail = temp;
count++; //а длина списка увеличится на 1 элемент
}

void dlist::del(int n) //проверка попадания в границы списка
{
if(n<1 || n>count)
{
cout << "No such position in dlist\n";
return;
}
int i = 1;
delem * del = head; //присваиваем временному элементу - указателю указатель на голову списка
while(i < n) //условие продолжения цикла - пока не дойдем до хвостового элемента
{
//доходим до элемента, который удаляется
del = del->next;
i++;
}

delem * prev_del = del->prev;//доходим до элемента, который предшествует удаляемому
delem * after_del = del->next;//доходим до элемента, который следует за удаляемым
if(prev_del != 0 && count != 1)
prev_del->next = after_del;
if(after_del != 0 && count != 1)
after_del->prev = prev_del;
if(n == 1) //специальный случай - удаление первого элемента
head = after_del;
if(n == count) //специальный случай - удаление последнего элемента
tail = prev_del;
delete del;
count--; //уменьшаем длину списка
}

dlist dlist::operator + (const dlist &t)
{
dlist result(*this);
delem * temp = t.head;
while(temp != 0)
{
result.to_tail(temp->data);
temp = temp->next;
}
return result;
}

dlist dlist::operator+(const delem t)
{
dlist result(*this);
result.to_tail(t.data);
return result;
}

delem dlist::operator [](int i)
{
if(i<1 || i>count)
{
cout << "Number out of the list" <<endl;
exit(1);
}
delem *temp=head;
for (int j=1; j<=i; ++j)
{
temp=temp->next;
}
return *temp;
}

dlist dlist::operator -(int i)
{
del(i);
return *this;
}

bool dlist::operator ==(dlist t)
{
return t.count==count;
}

bool dlist::operator >(dlist t)
{
return count>t.count;
}

ostream& operator<<(ostream& stream, dlist t)
{
delem temp=t.get_head();
do
{
stream<<temp.data<<endl;
}
while (temp.next);
return stream;
}


int main()
{
cout << "Hello" << endl;
//какая - нить хня
str one;
one.echo_data();
str two(5);
two.echo_data();
str three("three");
three.echo_data();
str four=one;
four.echo_data();
three=two;
three.echo_data();
two=three;
two.echo_data();
two="dfjhbdjfhvbjk";
two.echo_data();
cout << "Bye" << endl;
delem d1;
delem d2(d1);
d1=d2;
dlist first;
first.to_tail("dfblk");
cout<<first;
return 0;
}

[/HTML]
38K
25 мая 2008 года
meloman
5 / / 10.05.2008
friend ostream &operator << (ostream& output, Array& arr);
це для виводу на екран,потім після опису класу потрібно повернути значеня відповілно
ostream& operator<< (ostream& output, Array& arr)
{
for(int i = 0; i < arr.size; i++)
{
output << arr.ptr << " ";
}
output << endl;
return output;
}
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
якщо винекнуть питання з перегрущкою вводу тоді все робиться аналогічно:
friend istream &operator >>(istream& input, Array& arr) ;
...
istream& operator>> (istream& input, Array& arr)
{
for(int i = 0; i < arr.size; i++)
{
input >> arr.ptr;
}
return input;
}
38K
26 мая 2008 года
sorrelcat
6 / / 17.04.2008
Дякую! А то все ніяк не працювало, так і здала
59K
04 апреля 2010 года
greenbrick
1 / / 04.04.2010
[QUOTE=<SCORP>;155913]по поводу потенциальной опасности можно поподробнее, пожалуйста?[/QUOTE]
Переопределять оператор приведения к указателю на char* опасно само по себе!!! Это может приводить неприятным ошибкам времени выполнения:
например есть функция
 
Код:
void DoSmthWithString( const char* str );

Есть два объекта:
 
Код:
char* obj1;
MyClass obj2;

Программист случайно ошибается и пишет:
 
Код:
DoSmthWithString( obj2 )

При этом там должно было быть obj1.

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

Если хочется приводить класс к строке, правильнее всего добавлять в интерфейс класса метод 'GetInString', возвращающий тот же результат, что и 'operator char*'. Так сделано, например, в стандартной библиотеке для std::string (метод 'c_str' вместо оператора приведения к 'char*')
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог