0

我有一个抽象基类和一个模板派生类。派生对象可以由派生对象的先前实例构造,例如一个整数。到目前为止,我们有

struct base {
  /* ...pure virtual functions here... */

  virtual ~base() = default;
  /* NO DATA */
};

template <class D>
struct derived : base {
  derived() = default;

  derived(int x, const derived& previous) {
    /* to construct I need access to previous.data_ */
  }

  /* ...overriden virtual functions here... */

  ~derived() = default;

  D data_;
};

请注意,派生类的构造函数需要访问派生对象的data_成员。previous现在我想创建一个函数,它将derived<D>通过将整数和 的前一个实例作为输入来构造类型的对象derived<D>,并返回一个指向 的指针base。问题是,由于用户将使用base类指针,函数应该如下所示:

template <class D>
std::shared_ptr<base> getNext(int x, std::shared_ptr<base> current) {
  return std::make_shared<derived<D>>(x, *current); /* ERROR */
}

正如您可能已经猜到的那样,这会产生一个编译错误,指出没有已知的从baseto转换derived<D>。我知道我可以使用的一件事是 astatic_cast<derived<D>&>(*current)因为基础对象的类型将始终是derived<D>,但理想情况下,我希望尽可能避免任何强制转换。任何想法如何克服这个问题>?提前致谢!

4

3 回答 3

1

您可以在基类中使用虚拟访问器函数,它告诉派生类是哪种类型。然后你可以static cast安全地使用来转换基类。

class Animal {
    virtual bool isDog() { return false; }
    virtual bool isCat() { return false; }
};

class Dog : public Animal {
    virtual bool isDog() { return true; }
};

class Cat : public Animal {
    virtual bool isCat() { return true; }
};

然后我可以像这样安全地转换基类:

Dog A;
Cat B;

Animal *unknown_animal = &A;

if (unknown_animal->isDog()) {
    Dog *dog = static_cast<Dog*>(unknown_animal);
}
else if (unknown_animal->isCat()) {
    Cat *cat = static_cast<Cat*>(unknown_animal);
}

如果您只需要知道派生类型而不需要访问它,访问器函数也很有用。

于 2013-10-18T14:45:35.417 回答
0

When you're working with a polymorphic class and find yourself needing to cast to the derived type, this is often a clue that something is wrong with the design. After all, why have virtual functions if you still need to get to the derived class? I'm not saying there are no exceptions to this -- but I will say they are few and far between.

In this case, you (think you) need to cast in order to clone the object. Instead, I'd provide a clone method on the base class (here called getNext). Make that virtual, override it in the derived class, and call that instead:

struct base {
public:
  virtual std::shared_ptr<base> getNext(int x) = 0;
};

template <typename D>
struct derived : public base
{
public:
  std::shared_ptr<base> getNext(int x)
  { 
    std::shared_ptr <derived> clone = std::make_shared <derived<d>> (x, *this);
    return std::static_pointer_cast <base> (clone);
  }
};
于 2013-10-18T14:41:36.787 回答
0

无论如何,您都不想使用static_cast它;您想要使用dynamic_pointer_cast(并检查结果以确保它可以转换为您的派生类型)。

如果您的界面具有填写Data对象所需的所有信息,则可以创建一个转换构造函数,以避免进行强制转换:

template<typename T>
class MyDerived : public Base
{
public:
    // other functions
    MyDerived(std::shared_ptr<Base> p)
    {
        // initialize _data
    }

private:
    Data _data;
};
于 2013-10-18T14:40:41.090 回答