【问题标题】:Casting specialized base pointer to derived pointer that specializes on additional template parameter ("adding on" a specialization)将专门的基指针转换为专门处理附加模板参数的派生指针(“添加”专门化)
【发布时间】:2014-11-08 07:00:17
【问题描述】:

我想将基类指针转换为派生类,以便利用派生类独有的一些方法。这是一个有效的简单示例的Ideone

template<typename A>
class Base {};

template<typename A, typename B>
class Derived : public Base<A> {
public:
    void doSomething() {}
};

int main() {
    Base<int>* foo = new Derived<int, double>;
    static_cast<Derived<int, double>*>(foo)->doSomething();
    return 0;
}

现在,问题是我的foo 实际上是模板类的成员,

template<typename A>
class Container
{
public:
    Base<A>* foo;
};

而在我投射的时候,我不知道A 是什么:

int main() {
    Container<int> container;
    container.foo = new Derived<int, double>;

    // a lot of code later...
    static_cast<Derived< /* ??? */ , double>*>(container.foo)->doSomething();

    return 0;
}

然后我想如果我能以某种方式将 A 的内容存储在我的基类中,这可能是可能的,例如

template<typename A>
class Base
{
public:
    static type template_type = A; // made-up syntax
};

这样我可以参考它

static_cast<Derived<container.template_type, double>*>(container.foo)->doSomething();

但根据this question,不可能在 C++ 中存储类型。

如何在不知道A 的情况下实现此演员阵容?

也就是说,我如何将专门的基指针转换为专门用于附加模板参数的派生指针?用较少的技术术语来说,我只想采用 Base 指针并附加形成 Derived 指针所需的其他特化。

【问题讨论】:

  • 你肯定知道 A 是什么,因为你有一个 Base 类型的对象,你正试图投射?
  • 这就是我一直在想的,但这很奇怪,我看不到在我的设置中知道A 的方法。让我再看一遍,也许再稍微编辑一下以说明原因。
  • @ajclinto - 不,你是对的。我想到了。我有同样的预感,但以前没有看到。我认为我设计用于打印Container 元素的实用函数必须是通用的,这就是为什么我认为我不知道A 会是什么。但是在跟踪代码之后,我意识到这个实用函数只有在特定类型AContainers 上被调用,所以即使之前感觉不对,硬编码一个类型A 实际上是正确的它会打印。逻辑有效!结束这个问题。
  • 我会关闭这个问题,但不会删除它,以防有人过来想做同样的事情。解决方案:更仔细地检查您的代码,看看您是否正在尝试制作一些不应该/曾经是通用的通用内容。

标签: c++ class templates inheritance c++11


【解决方案1】:

通常进行向上转换是不明智的,通常有一个更好的设计可以用来完全避免向上转换的需要,但如果你真的需要它,那么你可以使用dynamic_cast这样做。

此运算符尝试动态地从一种类型转换为另一种类型,如果无法转换,它将返回nullptr。但请记住,它仅适用于多态类型(具有至少一个 virtual 函数的类型),因此在这种情况下,您的 Base 类必须是多态的(因为您持有指向基类的指针,您可能需要一个虚拟析构函数允许delete 在基指针上工作,这使得Base 成为一个多态类)。

但要记住 C++ 中的类型,您有两个选择:

  • 使用typedef:

您可以使用 typedef 来保存类中的类型信息:

template< class A >
class my_class
{
public:
    typedef A    input_type;
};

template< class T >
void do_something(T const& t)
{
     typename T::input_type n;
     do_something_on_input_type(n); // possibly overloaded for different input types
}

这种方法非常快,并且在运行时没有开销,但您只能在您想在编译时做某事的情况下使用它。如果指针的类型直到运行时才确定,这种方法就没有用了。

使用它,您实际上可以在类中保存类型信息:

class Base { virtual std::type_info const& get_type() const = 0; };
class Child : public Base
{
    virtual std::type_info const& get_type() const { return typeid(Child);
    void child_specific_function() { /**/ }
}
class ChildOfChild : public Child
{
    virtual std::type_info const& get_type() const { return typeid(ChildOfChild); }
    // ...
};

void do_something(Base* base)
{
    if (base->get_type() == typeid(Child))
    {
        static_cast<Child*>(base)->child_specific_function();
    }
}

这听起来很有趣,但它仅在您知道对象的确切类型并且它不适用于派生类型时才有用,因此这种方法适用于Child,但不适用于ChildOfChild

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-12
    • 1970-01-01
    • 2012-05-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多