正向声明在c++中不起作用.它表示初始化的类型不完整



我正在学习设计模式,并尝试实现构建器模式。为了这个目的,我用";clang++-std=c++17";但是我犯了错误";错误:初始化不完整的类型"HtmlBuilder"在静态函数HtmlElement::build中返回。如何解决这个问题?

class HtmlBuilder;
class HtmlElement
{
friend class HtmlBuilder;
string name, text;
vector<HtmlElement> elements;
const size_t indent_size = 2;
HtmlElement() {}
HtmlElement(const string &name, const string &text): name(name), text(text) {}
public:
string str(int indent = 0) const
{
ostringstream oss;
string i(indent_size*indent, ' ');
oss << i << "<" << name << ">" << endl;
if (text.size() > 0)
{
oss << string(indent_size * (indent + 1), ' ') << text << endl;
}
for (const auto& e: elements)
{
oss << e.str(indent + 1);
}
oss << i << "</" << name << ">" << endl;
return oss.str();
}
static HtmlBuilder build(const string& root_name)
{
return {root_name};
}
};
class HtmlBuilder
{
HtmlElement root;
public:
HtmlElement build()
{
return root;
}
HtmlBuilder(const string& root_name)
{
root.name = root_name;
}
HtmlBuilder& add_child(const string& child_name, const string& child_text)
{
HtmlElement e{child_name, child_text};
root.elements.emplace_back(e);
return *this;
}
string str() const
{
return root.str();
}
};
int main(int argc, char const *argv[])
{
HtmlBuilder builder("ul");
builder.add_child("li", "apple").add_child("li", "orange");
cout << builder.str() << endl;
return 0;
}

编辑-build返回对象而不是引用。

正如第一条注释所指出的,您需要将声明定义分离,否则编译器将被迫同时处理这两个问题。

在您的原始代码中:

class HtmlBuilder;
class HtmlElement
{
friend class HtmlBuilder;
public:
static HtmlBuilder build(const string& root_name)
{
return {root_name};
}
};

在这里,编译器被指示构造并返回它只知道名称的东西,它对如何创建其中一个一无所知。这就是你犯错误的地方。相反,如果你将其拆分,并有一个标题文件,如:

// html_element.h
class HtmlBuilder;
class HtmlElement
{
friend class HtmlBuilder;
public:
static HtmlBuilder build(const string& root_name);
};

这里可以理解的是,涉及到了一种名为HtmlBuilder的东西,目前尚不清楚这是什么,但只要最终得到解释,这就没关系。

然后稍后在实现文件中:

#include "html_builder.h"
#include "html_element.h"
HtmlBuilder HtmlElement::build(const string& root_name)
{
return {root_name};
}

这意味着它不需要确切地知道如何制作,它只需要有一个大致的想法,当你的实现被处理时,一切都清楚了,因为头文件已经被处理了。

注意,您不应该像JaMiT所指出的那样返回对临时的引用,所以我已经从代码中删除了它。

将声明(.h.hpp,您可以选择(与定义/实现(.cpp)(分离是一种很好的做法,以避免类似的陷阱。这也使在使用代码时更容易找到东西。

相关内容

最新更新