Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用继承类从模板类继承_C++_Templates_Inheritance_Interface - Fatal编程技术网

C++ 使用继承类从模板类继承

C++ 使用继承类从模板类继承,c++,templates,inheritance,interface,C++,Templates,Inheritance,Interface,当我从类继承时,编译器必须知道基类的定义才能创建它。但是,当我使用自己的继承类从模板类继承时,编译器如何创建代码?它还不知道班级的规模 #include <iostream> template <class T> class IFoo { public: virtual T addX(T foo, double val) = 0; // T memberVar; // uncomment for error }; class Foo : publi

当我从类继承时,编译器必须知道基类的定义才能创建它。但是,当我使用自己的继承类从模板类继承时,编译器如何创建代码?它还不知道班级的规模

#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未定义,正如我所预料的那样。

对于模板类IFoo的定义,编译器不需要知道Foo的大小来布局IFoo

Foo在这个上下文中是一个不完整的类,不是未定义或未声明的,并且可以以任何不完整类型都可以使用的方式使用。出现在成员函数参数列表中是可以的。将成员变量声明为Foo*很好。禁止将成员变量声明为Foo,这是必需的完整类型。

使用此模板类IFoo的定义,编译器无需知道Foo的大小即可布局IFoo


Foo在这个上下文中是一个不完整的类,不是未定义或未声明的,并且可以以任何不完整类型都可以使用的方式使用。出现在成员函数参数列表中是可以的。将成员变量声明为Foo*很好。将成员变量声明为Foo是不允许的,因为需要完整类型。

这里的一般概念称为奇怪的重复模板模式或CRTP。在上面搜索会得到很多点击率。请参阅:

不过,有一个简单的解释可能会回答您的问题,而不会过多地涉及CRTP。在C和C++中允许以下情况:

struct foo {
    struct foo *next;
    ...
};
或具有两种类型:

struct foo;
struct bar;

struct foo {
    struct bar *first;
    ...
};

struct bar {
    struct foo *second;
    ...
};

只要只使用指向结构或类的指针,类型的完整定义就不必可用。可以通过多种方式将模板分层,并且必须清楚地分别说明模板参数化的类型及其在模板中的使用。添加SFINAE替换失败并不是一个错误,人们甚至可以使没有被实例化的模板得到实例化,因为事情不能用给定的类型来完成。

这里的一般概念称为奇怪的重复模板模式或CRTP。在上面搜索会得到很多点击率。请参阅:

不过,有一个简单的解释可能会回答您的问题,而不会过多地涉及CRTP。在C和C++中允许以下情况:

struct foo {
    struct foo *next;
    ...
};
或具有两种类型:

struct foo;
struct bar;

struct foo {
    struct bar *first;
    ...
};

struct bar {
    struct foo *second;
    ...
};
只要只使用指向结构或类的指针,类型的完整定义就不必可用。可以通过多种方式将模板分层,并且必须清楚地分别说明模板参数化的类型及其在模板中的使用。在SFINAE中添加替换失败并不是一个错误,人们甚至可以使没有替换的模板得到实例化,因为在给定类型下无法完成任务

编译器如何创建代码

回答这个问题和回答这个问题是一样的:编译器如何编译它

如何定义一个不存在的类型并声明一个使用该类型的函数

答案很简单:没有真正使用不存在的类型进行编译的代码。既然没有代码可编译,它怎么会失败呢

现在,您可能想知道is与您的代码有什么关系?它如何使一个类能够将自己作为模板参数发送给它的父类

让我们分析编译器在执行此操作时看到的内容:

struct Foo : IFoo<Foo> { /* ... */ };
编译器现在知道Foo存在,但它是一个不完整的类型

现在,他看到:

... : IFoo<Foo> ...
实际上,它声明了一个类,其中声明了一个函数。您在上面看到,使用不完整类型声明函数是有效的。同样的情况也发生在这里。此时,您的代码是可能的,因为此代码是:

struct Foo;
template struct IFoo<Foo>; // instanciate IFoo with Foo
太好了!它是否开始看起来与您使用纯虚拟函数的示例完全相同?让我们进行另一个有效转换:

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();
}
声明不完整类型的变量没有意义

编译器如何创建代码

回答这个问题和回答这个问题是一样的:编译器如何编译它

如何定义一个不存在的类型并声明一个使用该类型的函数

答案很简单:没有真正使用不存在的类型进行编译的代码。既然没有代码可编译,它怎么会失败呢

现在,您可能想知道is与您的代码有什么关系?它如何使一个类能够将自己作为模板参数发送给它的父类

让我们分析编译器在执行此操作时看到的内容:

struct Foo : IFoo<Foo> { /* ... */ };
编译器现在知道Foo存在,但它是一个不完整的类型

现在,他看到:

... : IFoo<Foo> ...
实际上,它声明了一个类,其中声明了一个函数。你看到ab了吗 声明类型不完整的函数是否有效。同样的情况也发生在这里。此时,您的代码是可能的,因为此代码是:

struct Foo;
template struct IFoo<Foo>; // instanciate IFoo with Foo
太好了!它是否开始看起来与您使用纯虚拟函数的示例完全相同?让我们进行另一个有效转换:

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();
}

声明一个不完整类型的变量是没有意义的。

memberVar会使Foo间接地持有它自己的另一个实例。基本上,这将使sizeofFoo==2*sizeofFoo。所以当然不行了-谢谢你所有漂亮的回答。现在我很清楚了,memberVar会让Foo间接地拥有它自己的另一个实例。基本上,这将使sizeofFoo==2*sizeofFoo。所以当然不行了-谢谢你所有漂亮的回答。现在我明白了。