【问题标题】:Proper way to inherit a class template from a base class while specializing the template在特化模板的同时从基类继承类模板的正确方法
【发布时间】:2019-05-10 00:37:42
【问题描述】:

我正在设计一个虚拟处理器,我想表示虚拟 CPU 将使用的不同大小的寄存器。我也想将它们包含在一个容器中,无论它们的实际大小和/或类型如何。

我会有一个看起来像这样的结构来存储寄存器

struct Memory {
    std::vector<std::shared_ptr<Register>> bank;
};

我正在尝试创建一个基本的空类:

struct Register {};

现在我将从这个基类继承来创建不同类型的受支持寄存器。这些寄存器还依赖于一些 typedef...

typedef std::int8_t   i8;
typedef std::int16_t i16;
typedef std::int32_t i32;
typedef std::int64_t i64;

typedef std::uint8_t   u8;
typedef std::uint16_t u16;
typedef std::uint32_t u32;
typedef std::uint64_t u64;

const u16 BYTE = 0x08, WORD = 0x10, DWORD = 0x20, QWORD = 0x40;

假设我想要一个寄存器,它的基础数据类型是 u8,另一个是 u16,依此类推...

struct Register8 : Register {
    u8 value;
    u8 getValue() const { return value; }
};

struct Register16 : Register {
    u16 value;
    u8 getValue() const { return value; }
};

struct Register32 : Register {
    u32 value;
    u32 getValue() const { return value; }
};

struct Register64 : Register {
    u64 value;
    u64 getValue() const { return value; }
};

所以这很简单,但是我不喜欢我对每个寄存器类的命名不同并且我看到除了类型不同之外的一些重复代码,所以我们应该能够创建一个模板...

struct Register{};

template<typename T>
Register_t : Register {
    T value;
    T getValue() const { return value; }
};

这很容易;但是我想专攻这个课程:

struct Register {};

template<typename T>
struct Register_t : Register {
    T value;
    T getValue() const { return value; }
};

template<>
struct Register_t<u8> {
    u8 value;
    u8 getValue() const { return value; }
};

template<>
struct Register_t<u16> {
    u16 value;
    u16 getValue() const { return value; }
};  

template<>
struct Register_t<u32> {
    u16 value;
    u16 getValue() const { return value; }
};

template<>
struct Register_t<u64> {
    u16 value;
    u16 getValue() const { return value; }
};  

好的,这又回到了我之前所说的关于重复代码的内容,我们正在引入更多,但是在我的情况下,这些将是唯一可以接受的类型,所以这种重复不是问题。

到目前为止一切都很好......

现在假设我尝试使用它...

ma​​in.cpp

#include <iostream>
#include "Register.h"

int main () {
    Register_t<u8> r8;
    r8.value = 8;
    Register_t<u16> r16;
    r16.value = 16;
    Register_t<u32> r32;
    r32.value = 32;
    Register_t<u64> r64; 
    r64.value = 64;

    Memory mem;
    mem.bank.push_back( std::make_shared<Register>( r8 ) );
    mem.bank.push_back( std::make_shared<Register>( r16 ) );
    mem.bank.push_back( std::make_shared<Register>( r32 ) );
    mem.bank.push_back( std::make_shared<Register>( r64 ) );

    return EXIT_SUCCESS;
};

好的,所以我成功地将这些作为共享指针存储到向量中。现在问题或问题来了......让我们尝试从类中访问这些值

int main () {
    // ....

    for ( auto& b : mem.bank ) {
        std::cout << b->getValue() << '\n'; // Uh oh class Register has no member getValue() ...
    }

    return EXIT_SUCCESS;
}

所以这是我的问题;我不知道如何间接调用继承类的getValue() 函数或如何正确继承这种类型的设计结构——类层次结构。或者如果我应该完全消除专业化......这就是我被困的地方,任何和所有的帮助都会很感激。

【问题讨论】:

  • 麻烦的是,编译器需要知道具体的类型才能做std::cout &lt;&lt; v之类的事情。但也许std::variantstd::visit 会对此有所帮助...
  • @aschepler 我正在考虑它们,但我试图以最少的开销保持它尽可能简单,同时还试图保持它的通用性和可移植性。另外我还不熟悉变体和访问......但可能是一个很好的练习或一个很好的练习......
  • @aschepler 我可以不用担心单个容器,并且为每种专业类型都有一个相应的容器,但我不想管理 4 个容器。
  • “这很简单;但是我想专门研究这个类:”您的专业化主要是基本情况(尽管您忘记了继承),所以不需要。跨度>
  • struct Register{ virtual ~Register() = default; virtual void print() const = 0; };using Register = std::variant&lt;Register_t&lt;u8&gt;, Register_t&lt;u16&gt;, Register_t&lt;u32&gt;, Register_t&lt;u64&gt;&gt;(并删除继承)。

标签: c++ templates inheritance c++17 template-specialization


【解决方案1】:

我认为你需要这样的东西:

struct Register {
    virtual int: getValue() = 0;
};

【讨论】:

  • 这不起作用,因为当我尝试在 main 中调用它时,Visual Studio 状态:'Register' 无法实例化抽象类,由于以下成员:,'int Register::getValue(void) ': 是抽象的,注意:参见 'Register::getValue' 的声明。 Visual Studio 的编译器错误为:C2259
  • @FrancisCugler 当然,因为现在您必须在每个子类中声明 getValue() 以返回 int
  • 但这不是我想要的行为。我希望能够返回与该寄存器完全相同的类型。
  • 这并不能解决问题,因为虚函数不能被不同的返回类型覆盖。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-04-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-19
  • 1970-01-01
相关资源
最近更新 更多