这个小程序必须编写一个xml文件。
构建代码时,出现以下错误:
K:\Sergio\cpp\xml\sergio\cbp6s\main.cpp|32|error: 'base_tag' is an inaccessible base of 'tag'
简而言之,我有两个派生自base_tag的类(xml_declaration和tag),我想在std :: map中插入(或放置)一些std :: pair元素。
构建时,第一个插入有效(std::pair<order::declaration, xml_declaration>
),但是第二个插入失败(std::pair<order::root, tag_object>
)。
对象之间是从base_tag
派生的
我在哪里错了?
文件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_
文件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;
}
文件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;
}
我在GCC 5.1.0(在Windows 10上)上使用Code :: Blocks。
答案 0 :(得分:1)
如错误消息所述,tag
是秘密继承base_tag
的。如果将其标题更改为
class tag: public base_tag;
(与您的xml_declaration
公开继承base_tag
一样),它将正式成为基本标记。
一个更严重的问题是,您尝试按值将继承的类的实例存储在基类的容器中。然后发生的是,对象被切成薄片并失去了它们的全部派生功能。您将派生类的对象放入映射中,但实际上在其中存储了基类的对象(这就是某些人倾向于说多态基类必须一定是抽象的原因。)使用(智能)指针或{{ 1}}是reference_wrapper
的映射类型。