Издательский дом ООО "Гейм Лэнд"ЖУРНАЛ ХАКЕР #58, ОКТЯБРЬ 2003 г.

Сколько плюсов у C++?

AvaLANche

Xakep, номер #058, стр. 058-090-3


// файл "mystring.h"

namespace MyString { // интерфейс

bool assign (char*); // присвоение значения

int length (); // возвращает длину строки

char* value (); // возвращает значение

}

Получился довольно примитивный модуль :). Теперь посмотрим на его реализацию.

// файл "mystring.с"

#include <string.h>

#include "mystring.h"

namespace MyString { // реализация

const int max_size = 1000; // максимальный размер

int len = 0; // длина

char v[max_size]; // массив символов

}

bool MyString::assign (char* str) {

if (strlen (str) > max_size - 1)

return false;

if (!strcpy (v, str))

return false;

else

return true;

}

int MyString::length () {

return len;

}

char* MyString::value () {

return v;

}

Теперь пользователю достаточно заинклудить mystring.h, и можно пользоваться нашей строкой:

// файл "user.c"

#include "mystring.h"

void f ()

{

if (!MyString::assing ("Yo!"))

cout << "Ошибка!";

else

cout << MyString::value ();

}

Абстракция данных

Используя модуль, описанный выше, ты в какой-то момент столкнешься с проблемой реализации нескольких таких строк. Действительно, трудно представить ситуацию, где достаточно одной подобной строки. Результатом долгих и тяжелых экспериментов над нашим модулем-строкой станет некое подобие типа данных, "псевдо тип" строка. Как это чудо сделать - описывать не буду, потому что такое решение проблемы далеко от идеала. На этот случай C++ припас свое решение - возможность определения типов, которые ведут себя почти как встроенные. Такие типы называются абстрактными или типами, определяемыми пользователем (пользовательскими). Просвещенные товарищи, знакомые с ООП, думаю, уже поняли, о чем речь.

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

class MyString {

int length; // длина

char* v; // массив символов

public:

// создает строку из C-строки cstr

MyString (char* cstr);

// создает пустую строку по умолчанию - нулевой длины

MyString ();

MyString operator+ (MyString); // конкатенация

bool operator== (MyString); // проверка на равенство

// и так далее...

};

Этот листинг демонстрирует объявление класса - пользовательского типа. Наш класс реализует строку и несколько операций над строками. По умолчанию все члены класса являются закрытыми (private), то есть доступ к ним имеют только функции-члены этого класса. Элементы, объявленные как "public", общедоступны. Сами функции-члены определяются примерно так:

bool MyString::operator== (MyString mystr)

{

return (strcmp (v, mystr.v) == 0);

}

Функция-член, имеющая то же название, что и класс, называется конструктором. Конструкторы помогают по-разному инициализировать объекты класса - конкретные переменные. Обычно в них выделяется необходимая память, инициализируются переменные и т.п. В MyString, как видно из листинга, два конструктора: один по умолчанию, другой преобразует C-строку в "нашенскую". Пользоваться классом MyString можно так:

Назад на стр. 058-090-2  Содержание  Вперед на стр. 058-090-4