Расширение векторного итератора для доступа к элементам данных содержащегося класса / структуры - PullRequest
2 голосов
/ 19 мая 2011

Итак, у меня есть класс, который выполняет строковые манипуляции на основе метаданных, прикрепленных к каждому символу в строке. Внутренне я представляю это с помощью std::vector<CharacterType>, где CharacterType содержит, помимо прочего, рассматриваемый символ. Это внутреннее представление полезно для меня, но в конце манипуляций с пользователем класс заинтересован в самой строке.

Чтобы сделать это, я решил расширить std::vector<CharacterType>::iterator, чтобы включить метод operator*(), который возвращает символ, а не CharacterType. Вот код, он работает в Visual Studio 2008 на Windows 7. Но это идиоматический C ++? Я не много писал на C ++ с 90-х годов, поэтому буду благодарен за отзыв о стиле или за то, что я делаю что-то опасное и / или злое. (В приведенном ниже коде я создал упрощенную структуру CharacterType, которая называется mytype - на самом деле структура немного больше.)

#include <iostream>
#include <vector>
#include <string>

struct mytype {
    char c;
};

class myit : public std::vector<mytype>::iterator {
public:
    inline myit(std::vector<mytype>::iterator const &c)
        : std::vector<mytype>::iterator(c) {}
    char operator*() {
        const mytype &p =
            std::vector<mytype>::iterator::operator*();
        return p.c;
    }

    // Added these in a later edit, after thinking about a comment below
    typedef char value_type;
    typedef char *pointer;
    typedef char &reference;

private:
};

int
main()
{
    mytype test[] = { {'a'}, {'b'}, {'c'}, {'d'} };
    std::vector<mytype> vec(&test[0], &test[4]);
    myit i(vec.begin()), e(vec.end());
    std::string str(i, e);

    std::cout << str << std::endl;
    return 0;
}

Если предположить, что это хороший стиль, уместно ли использовать перегрузку методов с учетом типов в C ++, чтобы в myit было несколько operator*() методов, чтобы я мог использовать один и тот же класс итератора для получения другого члена другого типа? Или лучше использовать шаблон? Например, одна часть метаданных - это язык персонажа, и я хотел бы иметь возможность извлечь std::vector<LanguageType> точно таким же образом. Мысли?

Кроме того, поскольку методы, которые возвращают эти данные, не влияют на внутреннее представление объекта, в интересах правильности констант я хотел бы иметь возможность определить методы доступа const. Это, вероятно, означает, что мне нужно изменить вышеприведенное, чтобы использовать вместо него const_iterator, но я еще не дошел до этого.

Спасибо за вашу критику стиля заранее!

Ответы [ 5 ]

0 голосов
/ 20 мая 2011

Несколько разных людей предложили мне посмотреть операторы преобразования, о которых, должен признать, я совершенно забыл.Решение, основанное на операторе преобразования, значительно чище:

#include <iostream>
#include <vector>
#include <string>

struct mytype {
    char c;
    inline operator char () { return c; }
};

int
main()
{
    mytype test[] = { {'a'}, {'b'}, {'c'}, {'d'} };
    std::vector<mytype> vec(&test[0], &test[4]);
    std::string str(vec.begin(), vec.end());

    std::cout << str << std::endl;
    return 0;
}

... и меня не беспокоит зловещее звучание, такое как нарушение контрактов итераторов STL.Кроме того, кажется (хотя я еще не пробовал), что если я хочу иметь возможность легко скопировать что-то, кроме строки (идея std::vector<LanguageType> в моем исходном вопросе), я могу легко расширить это, просто добавив другойоператор приведения, в то время как метод деривации итератора потребовал бы гораздо большего количества шаблонов, поскольку в C ++ полиморфизм возвращаемого типа отсутствует, как мне указали несколько человек.

Большое спасибо за ваши ответы, как только я получуЯ сделаю это, если вам интересно, почему я еще этого не сделал.

0 голосов
/ 19 мая 2011

Вы нарушаете несколько контрактов итераторов, возвращая тип, отличный от CharacterType, из operator*().Честно говоря, просто дайте CharacterType operator char(), если вы отчаянно хотите, чтобы они были конвертируемыми.

0 голосов
/ 19 мая 2011

Вы не должны получать std :: vector (или другие контейнеры STL), потому что его деструктор не является виртуальным, и вы можете столкнуться с ситуациями, когда деструктор вектора не вызывается, и вы получаете утечки памяти.

0 голосов
/ 19 мая 2011

Я не верю, что вы можете иметь "несколько operator*() перегрузок" в одном классе;по-видимому, вы хотели бы устранить неоднозначность на основе возвращаемого типа, но C ++ этого не делает.

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

0 голосов
/ 19 мая 2011

Прежде всего, я бы хотел написать такой хороший C ++ после такого долгого перерыва, если это когда-нибудь случится со мной!

сказал, что, по каким причинам вы исключаете простой оператор преобразования из вашего CharacterType в char? что-то вроде: CharacterType::operator char();

конечно, мы все знаем проблемы с перегрузкой операторов (но это не изменится в двух случаях) ...

о других вещах, которые вы спрашиваете, вы не можете перегружать в зависимости от типа возвращаемого значения, поэтому вы не можете иметь разные операторы () для разных типов возвращаемых данных, если вы это имеете в виду.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...