Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Наследование от контейнера STL.


Автор: andrew_121 25.5.2009, 00:38
Опять сабж.

Для работы со строками приходится пользоваться алгоритмами. Надоело постоянно вписывать бегины/энды.
Написал свой класс наследник std::string. Знаю что прямое наследование от STL контейнеров не лучшая идея.

Интересует Ваше мнение. Хорошо? Плохо? Почему?

Спасибо!

Автор: Earnest 25.5.2009, 08:15
Гуру считают, что плохо. Вообще наследование от конкретных классов плохо.
В основном, вопросы поддержки. Со временем функциональность расползается (как в базовом классе, если он конкретный, так и в производном), проект теряет четкость, существенные изменения становится трудно вносить... Как раз в этом смысле более безопасно наследование от стандартных классов (т.к. они не меняются). Но не кошерно. Лучше уж обертку сочинить.

Но, ИМХО, иногда, если аккуратно и локально, то можно... 
Кстати, твоя аргументация (зачем тебе наследоваться от string, begin\end не нравятся) как-то неубедительна. Во-первых, у строки куча своих алгоритмов, во вторых, стандартные алгоритмы все через begin\end работают - чего разнобой вносить.... И т.д.

Автор: mrbrooks 25.5.2009, 08:32
Цитата(andrew_121 @  25.5.2009,  00:38 Найти цитируемый пост)
Интересует Ваше мнение. Хорошо? Плохо? Почему?

зачем?

Автор: andrew_121 25.5.2009, 08:49
Цитата(Earnest @  25.5.2009,  08:15 Найти цитируемый пост)
Кстати, твоя аргументация (зачем тебе наследоваться от string, begin\end не нравятся) как-то неубедительна. Во-первых, у строки куча своих алгоритмов

Не достаточно. Просто есть необходимость кое-что добавить/заменить/изменить.

Автор: mes 25.5.2009, 08:51
Цитата(andrew_121 @  24.5.2009,  23:38 Найти цитируемый пост)
Написал свой класс наследник std::string. Знаю что прямое наследование от STL контейнеров не лучшая идея.


Не будет полиморфного удаления, так как базовый деструктор не виртуальный.

Цитата(andrew_121 @  24.5.2009,  23:38 Найти цитируемый пост)
Для работы со строками приходится пользоваться алгоритмами. Надоело постоянно вписывать бегины/энды.

а сделать набор функций оберток над алгоритмами ?


Цитата(andrew_121 @  24.5.2009,  23:38 Найти цитируемый пост)
Интересует Ваше мнение. Хорошо? Плохо? Почему?

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

Автор: azesmcar 25.5.2009, 09:09
Цитата(andrew_121 @  25.5.2009,  08:49 Найти цитируемый пост)
Не достаточно. Просто есть необходимость кое-что добавить/заменить/изменить. 

Почитайте Саттера - особенно главу - Ослабленная монолитность std::string. В нем и так до хрена функций а вы еще хотите добавить smile 

Классы СТЛ не писали в расчете не наследование. Открыто наследовать классы не предназначенные для этого - неправильно (мое лично мнение).
Закрытое наследование - вполне приемлемо.

Автор: Alek86 25.5.2009, 09:21
Цитата(mes @  25.5.2009,  08:51 Найти цитируемый пост)
а сделать набор функций оберток над алгоритмами ?

а заюзать, наконец, буст? в частности, "Boost String Algorithms Library";)

andrew_121, или буст или напиши враппер, что будет делать то, что тебе нужно

Автор: Earnest 25.5.2009, 09:27
Или просто набор глобальных функций, которые будут принимать строку. Это лучше, чем наследовать класс.

Автор: andrew_121 25.5.2009, 09:42
Цитата(mes @  25.5.2009,  08:51 Найти цитируемый пост)
Не будет полиморфного удаления, так как базовый деструктор не виртуальный.

Да, и в правду. Не подумал об этом.


Цитата(mes @  25.5.2009,  08:51 Найти цитируемый пост)
а сделать набор функций оберток над алгоритмами ?

Тогда лучше boost::string_algo заюзать.


Цитата(mes @  25.5.2009,  08:51 Найти цитируемый пост)
Имхо, плохо (но для общего случая.. чтоб сказать конкретно, надо видеть, чего Вы написали.)

Код


#ifndef __LSTRING_H__
#define __LSTRING_H__

#include <string>
#include <vector>
#include <algorithm>

#include "lstringlist.h"

/***************************************************************************/

class LString:public std::string {
public:
    LString():std::string() {}
    LString(const char* s):std::string(s) {}
    LString(const std::string& s):std::string(s) {}
    virtual ~LString() {}
    /**/
    LString& operator() (iterator b, iterator e) {
        resize(e-b);
        std::copy(b, e, begin());
        return *this;
    }
    LString& operator() (const_iterator b, const_iterator e) {
        resize(e-b);
        std::copy(b, e, begin());
        return *this;
    }
    /**/
    LString& operator= (value_type* it) {
        size_type len = strlen(it);
        resize(len);
        std::copy(it, it+len, begin());
        return *this;
    }
    LString& operator= (const value_type* it) {
        size_type len = strlen(it);
        resize(len);
        std::copy(it, it+len, begin());
        return *this;
    }
    /**/
    bool operator! () const { return length() == 0; }
    /**/
    int find(value_type c) const {
        return pos(c);
    }
    int find(value_type c, int p) const {
        return pos(c, p);
    }
    int find(const value_type* c) const {
        return pos(c);
    }
    int find(const value_type* c, int p) const {
        return pos(c, p);
    }
    /**/
    int pos(value_type c) const {
        const_iterator it = std::find(begin(), end(), c);
        if ( it == end() ) return -1;
        return it - begin();
    }
    int pos(value_type c, int p) const {
        const_iterator it = std::find(begin() + p, end(), c);
        if ( it == end() ) return -1;
        return it - begin();
    }
    int pos(const value_type* c) const {
        const_iterator it = std::search(begin(), end(), c, c+strlen(c));
        if ( it == end() ) return -1;
        return it - begin();
    }
    int pos(const value_type* c, int p) const {
        const_iterator it = std::search(begin() + p, end(), c, c+strlen(c));
        if ( it == end() ) return -1;
        return it - begin();
    }
    /**/
    bool contains(value_type c) const {
        return pos(c) != -1;
    }
    bool contains(value_type* c) const {
        return pos(c) != -1;
    }
    bool contains(const LString& s) const {
        return pos(s.data()) != -1;
    }
    /**/
    bool is_empty()                    const { return length() == 0; }
    operator const value_type*    () const    { return data();            }
    operator value_type*            ()            { return (char*)data();    }
    /**/
    LString mid(int b, int n = -1) const {
        int len = (n == -1) ? length()-b : n;
        return substr(b, len);
    }
    LString left( int count ) const {
        return mid( 0, count );
    }
    LString right( size_type count ) const {
        if ( count > length() )
            count = length();
        return mid( length() - count, count );
    }
    /**/
    LStringList split(value_type c) const {
        LStringList final;
        int j = 0;
        int i = find(c, j);
        int l = length();

        while ( i != -1 ) {
            if ( i > j && i <= l )
                final << mid(j, i - j);
            j = i + 1;
            i = find(c, j);
        }

        if ( mid(j, l-j+1).length() > 0 )
            final << mid(j, l-j+1);

        return final;
    }

    void replace(value_type c1, value_type c2) {
        if ( c1 == c2 ) return;
        iterator p = begin();
        while ( p < end() ) {
            p = std::find(p, end(), c1);
            if ( p == end() ) return;
            if ( c2 == '\0' ) {
                iterator f = std::copy(p+1, end(), p);
                *f = '\0';
                resize( std::find(begin(), end(), 0) - begin() );
            } else {
                *p = c2;
            }
            p++;
        }
    }
};

/***************************************************************************/

#endif // __LSTRING_H__


Код


#ifndef __LSTRINGLIST_H__
#define __LSTRINGLIST_H__

#include <vector>

class LString;
/***************************************************************************/

class LStringList:public std::vector<LString> {
public:
   LStringList():std::vector<LString>() {}
   LStringList( const LString& o ):std::vector<LString>() { add(o); }
   LStringList( const LStringList&);
    virtual ~LStringList() { clear(); }
   /**/
   LStringList& operator<< ( const LString&);
   LStringList& operator+= ( const LString&);
   LStringList& operator+= ( const LStringList&);
   void add( const LString&);
   bool contains(const LString&) const;

    LString join(const LString&) const;
   LStringList grep(const LString& str);
   
   bool is_empty() const { return empty(); }
};

/***************************************************************************/

#endif // __LSTRINGLIST_H__



Автор: mes 25.5.2009, 11:47
ну и зачем Вам наследовать интерфейс класса std::string ?  ради метода length () и нескольких тайпдефоф ?
не легче ли просто открыть к нему доступ, через метод  ? (например так std::string& LString::std(); и для const).
как минимум избавитесь от путаницы методов.






Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)