Gibs
Gibs

Reputation: 774

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.

Upvotes: 0

Views: 79

Answers (2)

Some programmer dude
Some programmer dude

Reputation: 409266

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).

Upvotes: 2

Jens
Jens

Reputation: 9416

XIniFile::open(const char *fn) calls addKey which is not a free function or a member of XIniFile. This is why you get the compiler error.

Some general design notes:

  • Try to not use friend classes or functions because they break encapsulation. Use the public interface.
  • Use C++ classes instead of C types for strings, vectors (instead of arrays)
  • Why do all classes have a virtual destructor? They don't have any virtual methods, so they are not good as a base class
  • Use C++ types instead of C types, e.g. C++ bool instead of int and FALSE
  • Use RAII wrappers instead of manual explicit heap-allocated objects. vector instead of new[], unique_ptr or shared_ptr etc.

Upvotes: 1

Related Questions