我有一个抽象基类和一个模板化的派生类。派生对象可以由派生对象的先前实例构造,例如,整数。到目前为止我们已经
了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 */
}
正如您可能已经猜到的那样,这会产生一个编译错误,指出没有从base
到derived<D>
的已知转换。我知道我可以使用的一件事是static_cast<derived<D>&>(*current)
,因为底层对象的类型总是derived<D>
,但理想情况下我想尽可能避免任何强制转换。
任何想法如何克服这个问题&gt;?提前谢谢!
答案 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);
}
};