gpt4 book ai didi

c++ - 使用 CRTP 的多态链中的两个继承级别

转载 作者:行者123 更新时间:2023-12-02 10:07:04 27 4
gpt4 key购买 nike

维基百科有一个 nice example这解释了如何使用 CRTP 模式来实现成员函数调用的多态链接。

该示例具有一个基类模板“Printer”和一个派生类“CoutPrinter”。我有一个类似的用例,但我需要一个额外的“中间”层。以下代码运行良好:

#include <iostream>

using namespace std;

template <typename T>
class Top
{
public:
Top(ostream &pstream) : m_stream(pstream) {}

T& top() { m_stream << "top\n"; return *static_cast<T*>(this); }

protected:
ostream& m_stream;
};

template <typename T>
class Middle : public Top<T>
{
public:
Middle(ostream &pstream) : Top<T>(pstream) {}

// why not just m_stream << "middle\n"; ?
T& middle() { static_cast<T*>(this)->m_stream << "middle\n"; return *static_cast<T*>(this); }
};

struct Bottom : public Middle<Bottom>
{
public:
Bottom(ostream &pstream) : Middle<Bottom>(pstream) {}

Bottom& bottom() { m_stream << "bottom\n"; return *this; }
};

int main()
{
Bottom(cout).bottom().middle().top().bottom().middle().top().middle().bottom();

return 0;
}


正如预期的那样,这将打印:
bottom
middle
top
bottom
middle
top
middle
bottom

top() 的实现是:
    T& top() { m_stream << "top\n"; return *static_cast<T*>(this); }

bottom() 的实现是:
    Bottom& bottom() { m_stream << "bottom\n"; return *this; }

gcc 和 clang 不会让我写:
    T& middle() { m_stream << "middle\n"; return *static_cast<T*>(this); }

因为他们认为 m_streammiddle() 范围内未声明.但是,两者都接受:
    T& middle() { static_cast<T*>(this)->m_stream << "middle\n"; return *static_cast<T*>(this); }

我不完全明白为什么 m_stream无法直接访问,并且额外添加了 thisT*是需要的。

我可以想象从 Middle的角度来看不可能弄清楚 Top 的每个(假设的)特化是否对于一些 T包含 m_stream成员,但 Bottom是一个具体的类,因此可以查看它自己的接口(interface)。

我想了解基本规则。

总结一下:为什么我们可以直接从Top和Bottom访问m_stream,而不能从Middle访问?

最佳答案

T& middle() { this->m_stream << "middle\n"; return *static_cast<T*>(this); }

这也将起作用。

模板方法不会查看依赖的基类,因为在您编译模板(而不是实例化它)时,编译器无法判断您是否引用了从 T 获得的基类成员。或同名的全局变量。

而不是让它在访问全局变量之间切换,这取决于 T包含,C++ 标准永远不会查看 T (和其他依赖于模板参数的基类)在查找名称时。

要查看类(class),请使用 this->或类似的。

这样,您将不会遇到某些 T 的情况。论据导致 m_stream是成员变量,而其他人则导致它成为全局变量。因为这会导致严重疯狂的错误。

现在, Bottom不遵守这些规则,因为 Middle<Bottom>不依赖于 Bottom 的任何(不存在的)模板参数.重要的是哪些基类的类型取决于您自己的模板参数。

所以在 Bottom ,它继承自 Middle<Bottom> 的事实和 Top<Bottom>是众所周知的。

顺便说一句,在基础 CRTP 类中,我经常有一个方法:
T& self() { return *static_cast<T*>(this); }
T const& self() const { return *static_cast<T const*>(this); }

作为一般模式。

然后我可以写:
T& middle() { this->m_stream << "middle\n"; return this->self(); }

别再胡闹了 static_cast到其他地方最衍生的 CRTP。

关于c++ - 使用 CRTP 的多态链中的两个继承级别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59718938/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com