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;
}
Перегрузка оператора <<
Пример класса:
class string
{
char *data;
public:
string(char *str) {strcpy(data, str);} // Конструктор
<type> operator << (<type>){???} // Метод перегрузки
}Object;
пользуемся поиском по форуму:
Код:
Код:
#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;
}
#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!!!!!!! поэтому перегружать надо не его!
Кроме того, что этот код потенциально опасен, он ещё и не делает того, что надо. Логично предположить, что даже при таком простейшем классе MyClass, пользователь захочет увидеть содержимое полей класса интерпретируемое специально для вывода, т.е. в даном случае хотя бы значение i, а не строку "my string".
а по поводу потенциальной опасности можно поподробнее, пожалуйста?
[/QUOTE]
Представь пример хотя бы с выводом i, и тогда вся "красота" видна и будет.
Кроме того, оператор приведения типов используется в одних случаях, а вот переопределенные оператор << совершенно в других и эти случаи концептуально разные. Не стоит мешать все в одну кучу.
[QUOTE=<SCORP>;155913]
а по поводу потенциальной опасности можно поподробнее, пожалуйста?[/QUOTE]
Ты возвращаешь char* на строковый литерал, сл-но можно спокойно попытаться писать в эту область:
Код:
int main()
{
MyClass c;
char* ch = c;
ch[0] = '\0';
cout << c << endl;
return 0;
}
{
MyClass c;
char* ch = c;
ch[0] = '\0';
cout << c << endl;
return 0;
}
ну по поводу использования оператора << спорить не буду -- никогда им пользовался, собссно :)
[/QUOTE]
В подобных случаях следует возвращать константные указатели.
[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]
це для виводу на екран,потім після опису класу потрібно повернути значеня відповілно
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;
}
Дякую! А то все ніяк не працювало, так і здала
Переопределять оператор приведения к указателю на char* опасно само по себе!!! Это может приводить неприятным ошибкам времени выполнения:
например есть функция
Код:
void DoSmthWithString( const char* str );
Есть два объекта:
Код:
char* obj1;
MyClass obj2;
MyClass obj2;
Программист случайно ошибается и пишет:
Код:
DoSmthWithString( obj2 )
При этом там должно было быть obj1.
Все прекрасно компилится, но работает далеко не так, как этого хотел программист.
Вот так вот. Примеров с подобным неправильным поведением программы из-за переопределенного оператора приведения типов можно придумать море.
Если хочется приводить класс к строке, правильнее всего добавлять в интерфейс класса метод 'GetInString', возвращающий тот же результат, что и 'operator char*'. Так сделано, например, в стандартной библиотеке для std::string (метод 'c_str' вместо оператора приведения к 'char*')