【问题标题】:C++: Use Derived-class-only variables from Base classC++:使用基类中的仅派生类变量
【发布时间】:2018-01-20 09:17:53
【问题描述】:

假设我有两个相似的结构 A 和 B。A 和 B 都有一个指向 A 的指针,但 A 有一个指向 A 或 B 的附加指针。

我想到了这样的东西,有一个 Base 和一个 Derived 类

template <bool T> struct Derived;
struct Base { Derived<0> *p1; };
template <> struct Derived<0> : public Base { Base *p2; };
template <> struct Derived<1> : public Base {};

其中 A 是 Derived&lt;0&gt;,B 是 Derived &lt;1&gt;

这里的问题是当通过p2访问一个类时,编译器不知道它是哪个Derived类,这样就会报错。

Derived<0> x, y, z;
x.p2 = &y;
y.p2 = &z;
x.p2->p2; // Error

你们中是否有人知道任何神奇的解决方法,最好只使用编译时功能?

我还需要知道我使用的是哪种类型的 Derived,以便我知道我是否可以使用 p2。

如果有帮助,您可以将事物可视化为双链表,其中Derived&lt;0&gt; 是普通节点,Derived&lt;1&gt; 是结束节点,p1prev 指针和p2next 指针。

编辑:它不需要使用Base-and-Derived-class-type结构,它可以是任何东西。

【问题讨论】:

  • 这是一个错误,因为x.p2 是指向Base 的指针,它没有p2 成员,因此-&gt;p2 无法解析任何内容。您可以dynamic_cast&lt;Derived&lt;0&gt;&gt;(x.p2) 并检查结果是否不是nullptr。如果不是,那么您可以通过强制转换的指针访问-&gt;p2
  • (注意基类必须是多态的,dynamic_cast 才能有条件地正确转换。)

标签: c++ templates template-specialization derived-class


【解决方案1】:

一种可能的解决方案是基于双重分派,这与最知名的访问者模式背后的想法相同。

它遵循一个最小的工作示例:

#include<iostream>

template<int>
struct Derived;

struct Visitor {
    template<int N>
    void visit(Derived<N> &);
};

struct Base {
    Derived<0> *p1;
    virtual void accept(Visitor &) = 0;
};

template<>
struct Derived<0>: public Base {
    void accept(Visitor &) override;
    Base *p2;
};

template<>
struct Derived<1>: public Base {
    void accept(Visitor &) override;
};

template<>
void Visitor::visit(Derived<0> &d) {
    std::cout << "Derived<0>" << std::endl;
    d.p2->accept(*this);
}

template<>
void Visitor::visit(Derived<1> &) {
    std::cout << "Derived<1>" << std::endl;
}

void Derived<0>::accept(Visitor &v) {
    v.visit(*this);
}

void Derived<1>::accept(Visitor &v) {
    v.visit(*this);
}

int main() {
    Visitor v;
    Derived<0> x, y;
    Derived<1> z;
    x.p2 = &y;
    y.p2 = &z;
    x.p2->accept(v);
}

wandbox 上查看并运行它。

如果你可以使用 C++17 和 std::variant,事情就简单多了:

#include<iostream>
#include<variant>

template<int>
struct Derived;

struct Base {
    Derived<0> *p1;
};

template<>
struct Derived<0>: public Base {
    std::variant<Derived<0> *, Derived<1> *> p2;
};

template<>
struct Derived<1>: public Base {};

struct Visitor {
    void operator()(Derived<0> *d) {
        std::cout << "Derived<0>" <<std::endl;
        std::visit(*this, d->p2);
    }

    void operator()(Derived<1> *) {
        std::cout << "Derived<1>" <<std::endl;
    }
};

int main() {
    Visitor v;
    Derived<0> x, y;
    Derived<1> z;
    x.p2 = &y;
    y.p2 = &z;
    std::visit(v, x.p2);
}

wandbox 上查看并运行它。

【讨论】:

    猜你喜欢
    • 2018-05-19
    • 1970-01-01
    • 2011-07-14
    • 1970-01-01
    • 2020-06-29
    • 1970-01-01
    • 1970-01-01
    • 2015-08-16
    • 2010-10-17
    相关资源
    最近更新 更多