Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
lr1.2012.docx
Скачиваний:
3
Добавлен:
24.11.2019
Размер:
13.72 Кб
Скачать
    1. Создание эффективных классов

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

MyString s1, s2("test"), s3=s2;

if(s1 == s2)

cout << "Строки равны" << endl;

else

cout << "Строки неравны" << endl;

s3 = s1 + s2;

cout << s1.length() << endl;

cout << s1 << endl;

cout << s2 << endl;

cout << s3 << endl;

Здесь к классу строки применяются стандартные операции языка. Да и само использование больше походит на применение обычных переменных языка. Такой класс просто использовать даже не зная описания этого класса. Рассмотрим, как нашему классу строки можно добавить такие свойства.

В языке Си++ есть своя специфика создания классов. Она связана с причинами создания и развития языка. Суть специфики такова, что язык не требует от вас строгого создания класса похожего на стандартный тип. Как вы увидели, вы вообще можете использовать класс как расширенный вид структур.

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

Посмотрим на реализацию класса строки в соответствии с описной идиомой. Сначала опишем класс:

class MyString {

public:

MyString();

MyString(char* s);

MyString(MyString s);

~MyString();

MyString operator=(MyString v);

MyString operator+(MyString v);

MyString operator ==(MyString v);

char operator[] (unsigned int i);

int length();

private:

friend istream operator >>(istream i, MyString s);

friend ostream operator <<(ostream o, MyString s);

char *ptr;

};

istream operator >>(istream i, MyString s);

ostream operator <<(ostream o, MyString s);

Как и раньше, класс имеет 3 конструктора и операция получения длины строки. Добавлены деструктор и операция присвоения. И переименованы операции сравнения и конкатенации. Добавлена операция обращения к символу строки. Операции ввода и вывода вынесены из класса и реализованы для использования напрямую с cout и cin.

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

Конечно, для практического использования нашего класса желательно добавить поддержку стандартной стоки Си. То есть присвоение и сравнение с типом char*, преобразование к этому типу и прочее.

    1. Реализация практических классов

Обыкновенно для реализации класса используют два файла: заголовочный файл и файл с исходным кодом. В заголовочном файле класс описывается, а в файле исходного кода реализуются методы. Такой способ организации позволяет повысить производительность при сборке программы. Операторы #ifndef MYSTRING_H и #define MYSTRING_H нужны для ограничения включения файла один раз в программу. Множественное включение приводит к ошибкам множественного определения и объявления. #endif указывает на окончание блока включения.

Приведем пример полной реализации класса строки.

#ifndef MYSTRING_H

#define MYSTRING_H

#include <iostream>

class MyString {

public:

MyString();

MyString(const char* s);

MyString(const MyString& s);

~MyString();

MyString& operator =(const MyString& v);

MyString operator +(const MyString& v) const;

bool operator ==(const MyString& v) const;

char operator [] (unsigned int i) const;

int length() const;

private:

friend std::istream& operator >>(std::istream& i, MyString& s);

friend std::ostream& operator <<(std::ostream& o, MyString& s);

char *ptr;

};

std::istream& operator >>(std::istream& i, MyString& s);

std::ostream& operator <<(std::ostream& o, MyString& s);

#endif // MYSTRING_H

Обратите внимание на const и &. В конце объявления метода const означает то, что метод может использоваться для константного экземпляра. При указании аргументов const гарантирует, что данные аргумента не будут изменены. А & позволяет передавать не все данные класса, а только адрес их расположения. Тип MyString& похож на тип const MyString*. Но только похож! Для прояснения различий рекомендую обратиться к Библиографическая ссылкаБиблиографическая ссылка.

Файл с кодом будет выглядеть так:

#include <cstring>

#include "mystring.h"

using namespace std;

MyString::MyString() {

*(ptr = new char[1])='\0';

}

MyString::MyString(const char* s){

ptr = new char[1];

strcpy(ptr, s);

}

MyString::MyString(const MyString& s) {

ptr = new char[1];

strcpy(ptr, s.ptr);

}

MyString::~MyString() {

delete[] ptr;

}

MyString &MyString::operator =(const MyString &v) {

strcpy(ptr, v.ptr);

return *this;

}

MyString MyString::operator +(const MyString &v) const {

MyString t(*this);

strcat(t.ptr, v.ptr);

return t;

}

bool MyString::operator ==(const MyString &v) const {

return !strcmp(ptr, v.ptr);

}

char MyString::operator [](unsigned int i) const {

return ptr[i];

}

int MyString::length() const {

return strlen(ptr);

}

istream& operator >>(std::istream& i, MyString &s) {

return i >> s.ptr;

}

ostream& operator <<(std::ostream& o, MyString &s){

return o << s.ptr;

}

Теперь мы имеем класс строки, который имеет возможность для практического применения в программе.

Библиография

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]