Search code examples
c++encapsulationabstraction

Accessing methods of an object from another object (Suggest for a better approach?)


I would like to preserve encapsulation and abstraction but I am really having trouble about editing this. I did this program in C and it worked but converting it to an OOP is really a headache for me. This program is an .ini file reader which has this format:

[sections] keys = values

XKey::XKey(const char *k, const char *v)
{
    free(m_name);
    free(m_value);
    m_name = strdup(k);
    m_value = strdup(v);
    m_next = 0;
}

XKey *XSection::addKey(const char *k, const char *v)
{
    XKey *kn = new XKey(k, v);
    XKey *ks;

    if (m_keys == 0) {
        m_keys = kn;
        return kn;
    }

    ks = m_keys;

    while (ks->m_next)
        ks = ks->m_next;

    ks->m_next = kn;
    return kn;
}

XKey::~XKey()
{

}

XSection::XSection(const char *s)
{
   free(m_name);
   m_name = strdup(s);
   m_next = 0;
   m_keys = 0;
}

XSection *XIniFile::addSection(const char *d)
{
    XSection *sn = new XSection(d);
    XSection *ss;

    if (m_sections == 0) {
        m_sections = sn;
        return sn;
    }

    ss = m_sections;

    while(ss->m_next)
        ss = ss->m_next;

    ss->m_next = sn;
    return sn;
}

XSection::~XSection()
{

}

XIniFile::XIniFile()
{
    m_sections = 0;
    m_modified = FALSE;
}

int XIniFile::open(const char *fn)
{   
    //do some routines here to get string values for 
    //sn               <--section name
    //kn               <--key name
    //val               <--value name
    //do loop here to insert all the sections   
            cs = addSection(sn);
            //do loop here to add all the keys and values on every section 
            //then move to the next section    
                addKey(kn, val);    

    return 0;
}

XIniFile::~XIniFile()
{
}

Here is a snippet of my .h file

class XKey
{
    friend class XSection;
    friend class XIniFile;

public:
    XKey(const char *, const char *);
    virtual ~XKey();

private:
    char *m_name;
    char *m_value;
    XKey *m_next;
};

class XSection
{
    friend class XIniFile;

public:
    XSection(const char *);
    XKey *addKey(const char *, const char *);
    virtual ~XSection();   

private:    
    char *m_name;
    XKey *m_keys;
    XSection *m_next;
};

class XIniFile
{
private:
    char *m_name;
    XSection *m_sections;
    int m_modified;

    XSection *addSection(const char *);

public:
    XIniFile();
    virtual ~XIniFile();
};

I hope you could understand the program that I am doing. Basically I am just storing them in a linked list.

I am having problems with this error addKey was not declared in this scope so I guess my approach is not really good.


Solution

  • Using what the C++ standard library gives you, you can simplify your code quite considerably.

    The class definition:

    class XIniFile
    {
    public:
        // Get a value
        std::string get(const std::string& section,
                        const std::string& key,
                        const std::string& dflt = "") const;
    
        // Set a value
        void set(const std::string& section,
                 const std::string& key,
                 const std::string& data);
    
    private:
        // Type alias to map a key to data inside a section
        using key_data_map_t = std::unordered_map<std::string, std::string>;
    
        // Type alias to map a section to a set of key-data pairs
        using section_map_t = std::unordered_map<std::string, key_data_map_t>;
    
        section_map_t sections;
    };
    

    The code:

    std::string XIniFile::get(const std::string& section,
                              const std::string& key,
                              const std::string& dflt /* = "" */)
    {
        auto section_iter = sections.find(section);
        if (section_iter != sections.end())
        {
            // Section found
            auto key_data_iter = section_iter->second.find(key);
            if (key_data_iter != section_iter->second.end())
            {
                // Key found
                return key_data_iter->second;
            }
        }
    
        // Section or key not found, return default value
        return dflt;
    }
    
    void XIniFile::set(const std::string& section,
                       const std::string& key,
                       const std::string& data)
    {
        sections[section][key] = data;
    }
    

    References:

    Notes: The std::unordered_map as well as the auto keyword for type deduction and the using keyword for creating type aliases are all new in C++11. It's supported by all major compilers latest versions (and in the case of GCC and Clang, not so latest).