从虚拟类继承的类的显式专用化

explicit specialization of a class that inherits from a virtual class

提问人:barony002 提问时间:11/6/2023 更新时间:11/6/2023 访问量:70

问:

我有一个虚拟类,以及一个实现虚拟函数的继承类BASEBOX_str

class BASE {
public:
    virtual ~BASE() {};

    virtual std::vector<int> custom_int() const = 0;

    virtual std::vector<double> custom_double() const = 0;
};

struct BOX_str final : public BASE {

    template <typename ...Args>
    BOX_str(Args... args) : base(std::forward<Args>(args)...) {}

    std::string base;

    std::vector<int> custom_int() const {
        return custom_vec<int>(base);
    }

    std::vector<double> custom_double() const {
        return custom_vec<double>(base);
    }

    template <typename NUM>
    std::vector<NUM> custom_vec(const std::string& s) const {
        return {32, 62};
    }
};

但是除了函数之外,所有类内容在类似类中都是通用的,BOX_strcustom_vec()

所以我试着做一个模板类BOX

template <typename T>
struct BOX : public virtual BASE {

    template <typename ...Args>
    BOX(Args... args) : base(std::forward<Args>(args)...) {}

    T base;

    std::vector<int> custom_int() const {
        return custom_vec<int>(base);
    }

    std::vector<double> custom_double() const {
        return custom_vec<double>(base);
    }

    template <typename NUM>
    std::vector<NUM> custom_vec(const T&) const;
};

并留待以后针对每个显式专业化实施custom_vec()BOX

template <>
struct BOX<std::string> {
    template <typename NUM>
    std::vector<NUM> custom_vec(const std::string& s) const {
        return {42, 52};
    }
};

然后我尝试测试类

int main() {
    std::string mystr{ "abcd" };

    BASE* v1 = static_cast<BASE*>(new BOX<std::string>(mystr));
    BASE* v2 = static_cast<BASE*>(new BOX_str(mystr));
}

v2没有提出任何错误,但确实: ,这意味着 的显式专用化无法访问其构造函数以及 的所有内容。v1excess elements in struct initializerBOXBOX

我被困住了,无法弄清楚如何正确实现该类,以便它以通用方式工作。将不胜感激。BOXBOX_str

C 虚拟函数 C++ 模板

评论

0赞 Fareanor 11/6/2023
为什么要将构造函数设为可变参数模板? 构造函数不接受任何参数,因此转发任何派生类的参数都是无用的,因为除了没有参数之外,没有任何东西是合格的。BASE
0赞 Fareanor 11/6/2023
此外,专业化不是派生类。专用化取代了通用定义(换句话说,您真正想要的是“子派生”类,而不是专用化)。
0赞 Some programmer dude 11/6/2023
不能对类或结构进行部分专业化。您必须进行完全、完全的重新实现。
0赞 Pete Becker 11/6/2023
术语:是一个抽象类,因为它具有(一个或多个)纯虚函数。“虚拟课堂”一词实际上没有任何意义,可能会与“虚拟基地”混淆。BASE

答:

1赞 Kozydot 11/6/2023 #1

您需要在专业化中再次提供类的完整定义,而不仅仅是函数:BOXcustom_vec()

template <>
struct BOX<std::string> : public virtual BASE {

    BOX(const std::string& s) : base(s) {}

    std::string base;

    std::vector<int> custom_int() const {
        return custom_vec<int>(base);
    }

    std::vector<double> custom_double() const {
        return custom_vec<double>(base);
    }

    template <typename NUM>
    std::vector<NUM> custom_vec(const std::string& s) const {
        return {42, 52};
    }
};

评论

0赞 barony002 11/6/2023
这就是我试图避免的,所有 s 内容的定义,除了在类之间更改的函数之外,它是BOXcustom_vec()
0赞 Kozydot 11/6/2023
正如您尝试的那样,在类的专用版本中定义方法将不起作用。当您将类专用化为 时,您正在创建一个全新的类,该类不会从原始模板继承任何内容。这就是构造函数和其他方法在专用类中不可用的原因。custom_vec()BOXBOXstd::stringBOXBOX<std::string>
2赞 YSC 11/6/2023 #2

与往常一样,任何问题*都可以通过额外的抽象层来解决:

define 调用一个尚未定义的:BOX::custom_vec::custom_vec

template <typename T>
struct BOX : public virtual BASE {
    // [...]

    template <typename NUM>
    std::vector<NUM> custom_vec(const T& v) const {
        return ::custom_vec<T, NUM>{}(v);
    }

然后,提供一个可以专门化并完全重新定义的结构,而不会无用的代码重复:

template<class BoxT, class BoxN>
struct custom_vec {};

template<>
struct custom_vec<std::string, int>
{ std::vector<int> operator()(std::string const&) const { return {42, 52}; } };

template<>
struct custom_vec<std::string, double>
{ std::vector<double> operator()(std::string const&) const { return {1.618, 3.14}; } };

编译器资源管理器演示


*除了有太多的抽象层

评论

0赞 barony002 11/6/2023
谢谢你的解决方案,空的双冒号是什么意思?return ::custom_vec<T, NUM>{}(v)
0赞 YSC 11/6/2023
这是“运算符”的范围。它使名称查找从不限定名称查找切换到限定名称查找。在这里,开关的作用是从全局命名空间而不是 .custom_vecBOX::custom_vec