Информация об изменениях

Сообщение Re: как лучше сделать от 26.02.2020 9:56

Изменено 26.02.2020 10:21 Erop

Re: как лучше сделать
Здравствуйте, sergey2b, Вы писали:

S>3) у класса есть метод setup но в нем передаеться только путь к файлу который этот класс будет обрабатывать

S>можно через эту строку передавать опции и внутри парсить
S>выглядит убого но все изменения затронут только один нужный мне класс


S>как лучше сделать добавление новых методов getOption setOption


1) Если во время существования объекта не надо иметь доступ к доп. параметрам, то мне тоже нравится решение от
rg45

2) Если же всё-таки нужны именно методы getOption setOption (например, есть какие-то версии доп. параметров для некоторых объектов и мы пробуем применять то одни, то другие), то можно пойти по python/smalltalk-style пути и передавать либо имя/ID доп. опции в методы getOption setOption БАЗЫ
либо std::map<std::string, int>
Но неудобно то, что динамики многовато для С++ и то, что если в разных классах понадобятся разные типы, то будет неудобно.
Хотя разные типы обеспечить более или менее можно

3) Завести структуру/класс ExtraOptions с виртуальным деструктором. Для тех классов, кому надо, выводить из неё расширенные версии.
В метод setOption передавать ссылку на такую структуру, а в методе класса dyn_cast'ом кастить вниз и получать доступ туда, куда нужно
А из getOption сразу возвращать выведенную структуру.

Вот пруф оф концепт:

https://www.ideone.com/e7bQ52

#include <iostream>
#include <string>
#include <map>
#include <assert.h>

struct IObj {
    //------ Подход 3 ----------------------------------------------
    struct ExtraOptionsBase {
        virtual ~ExtraOptionsBase() {}
    };    
    
    virtual void SetEO( ExtraOptionsBase& ) = 0; // Можно сделдать дефолтную пустую реализацию
    virtual ExtraOptionsBase& GetEO() = 0;

    //------ Подход 2 ----------------------------------------------
    virtual bool SetOption( const std::string& name, const int& value )  { return false; }
    virtual bool TryGetOption( const std::string& name, int& value ) { return false; }
    virtual bool SetOption( const std::string& name, const std::string& value ) { return false; }
    virtual bool TryGetOption( const std::string& name, std::string& value ) { return false; }
    
    template<typename T> T GetOption( const std::string& name ) {
        T res = T();
        bool is_ok = this->TryGetOption( name, res ); 
        assert( is_ok );
        return res;
    }    
};

template<typename T>
struct CObj : public IObj {
    //------ Подход 3 ----------------------------------------------
    struct ExtraOptions : public IObj::ExtraOptionsBase {
        T Param1;
        T Param2;
        
        T* getField( const std::string& name ) {
            if( name == "Param1" )
                return &this->Param1;
            if( name == "Param2" )
                return &this->Param2;
            return 0;
        }
    } Data;
    
    virtual ExtraOptions& GetEO() { return this->Data; }
    virtual void SetEO( ExtraOptions& ed ) { this->Data = ed; }
    virtual void SetEO( ExtraOptionsBase& ed ) { this->Data = dynamic_cast<ExtraOptions&>(ed); }
    
    //------ Подход 2 ----------------------------------------------
    virtual bool SetOption( const std::string& name, const T& value ) {
        T* field = this->Data.getField( name );
        if( field ) {
            *field = value;
            return true;
        }
        return false;
    }
    
    virtual bool TryGetOption( const std::string& name, T& value ) { 
        T* field = this->Data.getField( name );
        if( field ) {
            value = *field;
            return true;
        }
        return false;
    }
};


using namespace std;

int main() {
    
    std::map<std::string, int> pi = {
        { "Param1", 5 },    
        { "Param2", 10 },    
    };
    CObj<int> oi1, oi2;
    for( auto i = pi.begin(); i != pi.end(); ++i )
        oi1.SetOption( i->first, i->second );
    oi2.SetEO( oi1.GetEO() );
    std::cout << oi2.GetEO().Param1 << " " << oi2.GetOption<int>( "Param2" ) << std::endl;
    
    std::map<std::string, std::string> ps = {
        { "Param1", "Hello" },    
        { "Param2", "world!" },    
    };
    CObj<std::string> os1;
    for( auto i = ps.begin(); i != ps.end(); ++i ) 
        os1.SetOption( i->first, i->second );
    std::cout << os1.GetEO().Param1 << " " << os1.GetOption<std::string>( "Param2" ) << std::endl;

    // your code goes here
    return 0;
}


выдаёт
5 10
Hello world!

[/cut]
Re: как лучше сделать
Здравствуйте, sergey2b, Вы писали:

S>3) у класса есть метод setup но в нем передаеться только путь к файлу который этот класс будет обрабатывать

S>можно через эту строку передавать опции и внутри парсить
S>выглядит убого но все изменения затронут только один нужный мне класс


S>как лучше сделать добавление новых методов getOption setOption


1) Если во время существования объекта не надо иметь доступ к доп. параметрам, то мне тоже нравится решение от
rg45

2) Если же всё-таки нужны именно методы getOption setOption (например, есть какие-то версии доп. параметров для некоторых объектов и мы пробуем применять то одни, то другие), то можно пойти по python/smalltalk-style пути и передавать либо имя/ID доп. опции в методы getOption setOption БАЗЫ
либо std::map<std::string, int>
Но неудобно то, что динамики многовато для С++ и то, что если в разных классах понадобятся разные типы, то будет неудобно.
Хотя разные типы обеспечить более или менее можно

3) Завести структуру/класс ExtraOptions с виртуальным деструктором. Для тех классов, кому надо, выводить из неё расширенные версии.
В метод setOption передавать ссылку на такую структуру, а в методе класса dyn_cast'ом кастить вниз и получать доступ туда, куда нужно
А из getOption сразу возвращать выведенную структуру.

https://www.ideone.com/e7bQ52
  "Вот пруф оф концепт: "
#include <iostream>
#include <string>
#include <map>
#include <assert.h>

struct IObj {
    //------ Подход 3 ----------------------------------------------
    struct ExtraOptionsBase {
        virtual ~ExtraOptionsBase() {}
    };    
    
    virtual void SetEO( ExtraOptionsBase& ) = 0; // Можно сделдать дефолтную пустую реализацию
    virtual ExtraOptionsBase& GetEO() = 0;

    //------ Подход 2 ----------------------------------------------
    virtual bool SetOption( const std::string& name, const int& value )  { return false; }
    virtual bool TryGetOption( const std::string& name, int& value ) { return false; }
    virtual bool SetOption( const std::string& name, const std::string& value ) { return false; }
    virtual bool TryGetOption( const std::string& name, std::string& value ) { return false; }
    
    template<typename T> T GetOption( const std::string& name ) {
        T res = T();
        bool is_ok = this->TryGetOption( name, res ); 
        assert( is_ok );
        return res;
    }    
};

template<typename T>
struct CObj : public IObj {
    //------ Подход 3 ----------------------------------------------
    struct ExtraOptions : public IObj::ExtraOptionsBase {
        T Param1;
        T Param2;
        
        T* getField( const std::string& name ) {
            if( name == "Param1" )
                return &this->Param1;
            if( name == "Param2" )
                return &this->Param2;
            return 0;
        }
    } Data;
    
    virtual ExtraOptions& GetEO() { return this->Data; }
    virtual void SetEO( ExtraOptions& ed ) { this->Data = ed; }
    virtual void SetEO( ExtraOptionsBase& ed ) { this->Data = dynamic_cast<ExtraOptions&>(ed); }
    
    //------ Подход 2 ----------------------------------------------
    virtual bool SetOption( const std::string& name, const T& value ) {
        T* field = this->Data.getField( name );
        if( field ) {
            *field = value;
            return true;
        }
        return false;
    }
    
    virtual bool TryGetOption( const std::string& name, T& value ) { 
        T* field = this->Data.getField( name );
        if( field ) {
            value = *field;
            return true;
        }
        return false;
    }
};


using namespace std;

int main() {
    
    std::map<std::string, int> pi = {
        { "Param1", 5 },    
        { "Param2", 10 },    
    };
    CObj<int> oi1, oi2;
    for( auto i = pi.begin(); i != pi.end(); ++i )
        oi1.SetOption( i->first, i->second );
    oi2.SetEO( oi1.GetEO() );
    std::cout << oi2.GetEO().Param1 << " " << oi2.GetOption<int>( "Param2" ) << std::endl;
    
    std::map<std::string, std::string> ps = {
        { "Param1", "Hello" },    
        { "Param2", "world!" },    
    };
    CObj<std::string> os1;
    for( auto i = ps.begin(); i != ps.end(); ++i ) 
        os1.SetOption( i->first, i->second );
    std::cout << os1.GetEO().Param1 << " " << os1.GetOption<std::string>( "Param2" ) << std::endl;

    // your code goes here
    return 0;
}


выдаёт
5 10
Hello world!