使用继承类从模板类继承
Inheriting from a template class using the inheriting class
从类继承时,编译器必须知道基类的定义才能创建它。但是,当我使用自己(继承类)从模板类继承时,编译器如何创建代码?它还不知道班级的大小。
#include <iostream>
template <class T> class IFoo
{
public:
virtual T addX(T foo, double val) = 0;
// T memberVar; // uncomment for error
};
class Foo : public IFoo<Foo>
{
public:
Foo(double value)
: m_value(value) {}
Foo addX(Foo foo, double b) override
{
return Foo(foo.m_value + b);
}
double m_value;
};
int main()
{
Foo foo1(1);
Foo foo2 = foo1.addX(foo1, 1);
std::cout << foo2.m_value;
}
首先,我认为它有效,因为它是一个接口,但也可以与常规类一起使用。
当我将模板存储为会员时,我会遇到一个错误,即FOO不确定,就像我预期的那样。
这里的一般概念称为奇怪的重复曲线模式或 crtp 。进行搜索将获得很多命中。请参阅:https://stackoverflow.com/questions/tagged/crtp。
但是,有一个简单的解释可能会回答您的问题而不会太多地进入CRTP。在C和C 中允许以下内容:
struct foo {
struct foo *next;
...
};
或两种类型:
struct foo;
struct bar;
struct foo {
struct bar *first;
...
};
struct bar {
struct foo *second;
...
};
只要使用struct
或class
的指针,就不必对该类型的完整定义。一个人可以以多种方式将模板层在此上面,并且必须清楚地清楚地对模板的参数化类型及其在模板中的使用。添加sfinae(替换失败不是错误),甚至可以制作没有实例化的模板,因为用给定类型无法完成事情。
使用template class IFoo
的定义,编译器不需要知道Foo
的大小即可布置IFoo<Foo>
。
Foo
将是此上下文中的不完整类(不是"未定义"或"未确定"),并且可以使用任何不完整类型的方式使用。出现在成员函数参数列表中是可以的。将成员变量声明为Foo*
是可以的。将成员变量声明为Foo
是禁止的(需要完整的类型)。
编译器如何创建代码?
回答这个问题与回答以下问题相同:编译器如何编译?
struct Type;
Type func(Type);
实时示例
如何定义一种不存在的类型,但声明使用该类型的函数?
答案很简单:实际上使用该不存在的类型没有代码可以编译。由于没有代码要编译,该如何失败?
现在,也许您想知道与您的代码有什么关系?它如何使一类可以将自己作为模板参数发送给父母?
让我们分析编译器在执行此操作时看到的内容:
struct Foo : IFoo<Foo> { /* ... */ };
首先,编译看到了:
struct Foo ...
编译器现在知道Foo
存在,但它是一种不完整的类型。
现在,他看到了:
... : IFoo<Foo> ...
它知道IFoo
是什么,并且知道Foo
是一种类型。现在,编译器只需要使用该类型将IFoo
实施:
template <class T> struct IFoo
{
virtual T addX(T foo, double val) = 0;
};
真的,它声明了一个类,并在其中声明了一个函数。您在上面看到了宣布具有不完整类型的功能的功能。同样的事情也是如此。那时,您的代码可能是可能的,因为此代码为:
struct Foo;
template struct IFoo<Foo>; // instanciate IFoo with Foo
所以真的没有巫术。
现在让我们以一个更具说服力的例子。那呢?
template<typename T>
struct IFoo {
void stuff(T f) {
f.something();
}
};
struct Foo : IFoo<Foo> {
void something() {}
};
编译器如何在不完整类型上调用something
?
事实是:不是。当我们使用something
时,Foo
已完成。这是因为模板函数仅在使用时就进行了实例化。
还记得我们可以将函数定义分开,即使使用模板?
template<typename T>
struct IFoo {
void stuff(T f);
};
template<typename T>
void IFoo<T>::stuff(T f) {
f.something();
}
struct Foo : IFoo<Foo> {
void something() {}
};
太好了!它是否开始看起来与纯虚拟函数的示例完全相同?让我们进行另一个有效的转换:
template<typename T>
struct IFoo {
void stuff(T f);
};
struct Foo : IFoo<Foo> {
void something() {}
};
// Later...
template<typename T>
void IFoo<T>::stuff(T f) {
f.something();
}
完成!在Foo
完成后,我们稍后定义该功能。而且这是事实的,发生的事情:编译器只有在使用时才会实施IFoo<Foo>::stuff
。Foo
的使用点已完成。那里也没有魔法。
为什么您不能在IFoo
内声明T
成员变量?
简单,出于同样的原因,该代码不会编译:
struct Bar;
Bar myBar;
声明不完整类型的变量是没有意义的。
- 继承函数的重载解析
- 继承期间显示未知行为的子类
- 头文件-继承c++
- 为什么在保护模式下继承升级不起作用
- 通过继承类使用来自不同命名空间的运算符
- 子目录是否继承属性,例如add_definitions,include_directories和父Cmakelist.t
- 混合组合和继承的C++问题
- 继承:构造函数,初始化C++11中基类的类C数组成员
- 从类继承时,继承的类是否会通过父类重新定义继承的变量
- 公共与私人继承
- 如何创建从同一类继承的不同对象的向量
- 如何从另一个文件继承私有成员变量和公共函数
- 在模板基类中为继承类中的可选重写生成虚拟方法
- 带有继承的C++工厂
- 我应该避免多重实现继承吗
- C++继承更改成员
- 从具有默认值的部分指定模板类继承时发生SWIG错误,具有不带默认值的正向声明
- 关于C++中具有多重继承"this"指针的说明
- 尝试使用继承和模板实现CRTP.Visual Studio正在生成编译器错误
- 如何在QT Creator上将QWidget声明为继承类的对象