c ++:如何避免static_cast?

时间:2013-10-18 14:27:22

标签: c++ inheritance abstract static-cast

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

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 */
}

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

3 个答案:

答案 0 :(得分: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);
}

如果只需知道派生类型,但不需要访问,访问者功能也很有用。

答案 1 :(得分: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;
};

答案 2 :(得分:0)

当您使用多态类并发现自己需要转换为派生类型时,这通常是设计出现问题的线索。毕竟,如果你仍然需要到派生类,为什么有virtual函数?我不是说这没有例外 - 但我会说它们很少而且很远。

在这种情况下,你(想你)需要强制转换以克隆对象。相反,我会在基类(这里称为clone)上提供getNext方法。设置virtual,在派生类中覆盖它,然后调用它:

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);
  }
};