0

This little program has to write an xml file. Building the code I get the following error: K:\Sergio\cpp\xml\sergio\cbp6s\main.cpp|32|error: 'base_tag' is an inaccessible base of 'tag'
In short, I have two classes derived from base_tag (xml_declaration and tag) and I want insert (or emplace) in a std::map some std::pair elements.
Building, the first insert works (std::pair<order::declaration, xml_declaration>), but the second fails (std::pair<order::root, tag_object>).
Between the object are derived from base_tag
Where am I wrong?

File tag.hpp :

#ifndef _TAG_HPP_
#define _TAG_HPP_

#include <string>
#include <vector>
#include <utility>

enum class tag_type
{
    closing = -1,
    autoclosed = 0,
    opening  = 1
};

using attribute = std::pair<std::string, std::string>;

class base_tag
{
public:
    base_tag();
    virtual ~base_tag();

    virtual std::string get();
    bool attribute_exists(std::string);
    std::string get_attribute_value(std::string name);
    bool add_attribute(std::string name, std::string value);

protected:

    std::vector<std::pair<std::string, std::string>> _attributes;
};

// ------------------------------------------------------------ 

class xml_declaration : public base_tag
{
public:
    xml_declaration();
    ~xml_declaration();
    std::string get();
};

// ----------------------------------------------------------

class tag : base_tag
{
public:
    tag(std::string name);
    tag(std::string name, tag_type tt );
    std::string get();
    void set_ident(size_t ident);

protected:
    std::string _name;
    tag_type _tt;
};

#endif // _TAG_HPP_

File tag.cpp

#include "tag.hpp"

base_tag::base_tag()
{
}

base_tag::~base_tag()
{
    _attributes.clear();
}

bool base_tag::attribute_exists(std::string name)
{
    bool res = false;

    for(auto & i : _attributes)
    {
        if (i.first == name)
            res = true;
    }

    return res;
}

bool base_tag::add_attribute(std::string name, std::string value)
{
    bool res = false;

    if(!attribute_exists(name))
    {
        attribute a = std::make_pair(name, value);
        _attributes.push_back(a);
        res = true;
    }
    return res;
}

std::string base_tag::get()
{
    return u8"<invalid_tag/>";
}

// -------------------------------------------------------

xml_declaration::xml_declaration(): base_tag()
{
    add_attribute("version", "1.0");
    add_attribute("encoding", "UTF-8");
    add_attribute("standalone", "yes");
}

xml_declaration::~xml_declaration()
{ }

std::string xml_declaration::get()
{
    std::string res = u8"<?xml";
    for(auto & i : _attributes)
    {
        res.push_back(' ');
        res += i.first;
        res += u8"=\"";
        res += i.second;
        res += u8"\"";
    }
    res += u8" ?>";
    return res;
}

// -------------------------------------------------------------

tag::tag(std::string name):base_tag(), _name(name)
{
    _tt = tag_type::autoclosed;
}

tag::tag(std::string name, tag_type tt ): base_tag(), _name(name), 
_tt(tt)
{ }

std::string tag::get()
{
    std::string res = u8"";

    bool with_attributes = !(_attributes.empty());
    switch(_tt)
    {
        case tag_type::autoclosed : {    
            res = u8"<";
            res += _name;
            if(with_attributes)
            {
                for(auto & i : _attributes)
                {
                    res.push_back(' ');
                    res += i.first;
                    res += u8"=\"";
                    res += i.second;
                    res += u8"\"";
                }
            };
                    res += u8"/>";
                    break;
        }

    case tag_type::opening :   {   
                    res = u8"<";
                    res += _name;
                    for(auto & i : _attributes)
                    {
                        res.push_back(' ');
                        res += i.first;
                        res += u8"=\"";
                        res += i.second;
                        res += u8"\"";
                    }
                        res += u8">";
                        break;
                            }

    case tag_type::closing :  {   
                        res = u8"</";
                        res += _name;
                        res.push_back('>');
                        }

    default :           break;

    }
    return res;
}

File main.cpp

#include <iostream>
#include <map>
#include <utility>
#include "tag.hpp"

using namespace std;

enum class order
{
    declaration     = 0,
    root            = 1,
    file_version    = 4,
    project         = 10,
    project_closing = 998,
    root_closing    = 1000
};

int main()
{
    std::map<order, base_tag> tree;

    xml_declaration decl;
    cout << decl.get() << endl;

    tag t1("project_file", tag_type::opening);
    tag t2("project_file", tag_type::closing);

    tree.insert(std::pair<order, base_tag>(order::declaration, 
decl));
    tree.insert(std::pair<order, base_tag>(order::root, t1));
    tree.insert(std::pair<order, base_tag>(order::root, t2));
//  tree.emplace(std::pair<order, base_tag>(order::root_closing, t1));

    cout << tree.size() << endl;

    return 0;
}

I'm using Code::Blocks with GCC 5.1.0 (on Windows 10).

1 Answer 1

1

As the error message says, tag inherits base_tag privately. If you change its headline into

class tag: public base_tag;

(same as your xml_declaration which inherits base_tag publicly) then it will officially be-a base tag.

A more serious problem is that you try to store instances of inherited classes in a container of a base class by value. What happens then is, objects get sliced and lose their whole derived functionality; you put an object of a derived class into a map, but you actually store an object of a based class in it (that's the reason some people tend to say polymorphic base classes should necessarily be abstract.) Use (smart) pointers or reference_wrappers as map's mapped type.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.