扩展现有的 C++ 类

Mik*_*ang 6 c++ inheritance downcast

我想在不更改现有类的情况下添加额外的功能。

说,

class base{
public:
    int i;
    base(){i = 1;}
    virtual void do_work(){ /*Do some work*/ }
};
Run Code Online (Sandbox Code Playgroud)

如果我想serialization向其中添加成员函数,我只需创建一个派生类

class derived : public base{
public:
    void serialize();
};

void derived::serialize(){
    cout << "derived class" << endl;
}
Run Code Online (Sandbox Code Playgroud)

我确实需要处理现有的base对象,例如

int main(){
    base a;
    derived & b = static_cast<derived &>(a);

    b.serialize();
}
Run Code Online (Sandbox Code Playgroud)

这个例子运行没有问题。但我确实知道一般情况下应该避免这种downcast情况static_cast

但我想知道对于downcast这一特定用例是否可以被认为是安全的,因为该类derived只有一个额外的成员函数。它是否会有一些潜在的未定义的访问行为vtable

Fre*_*ddy 5

您扩展的方式Base没有利用,vtable因为您没有virtual方法。将其视为更容易Derived has A Base;您创建了一个包含Base成员变量的新类。

我的建议。

模板函数

我个人会选择模板函数。您可以将所有工作保留在原始问题中,并避免virtual向类添加调用。

template<typename T>
void serialize_object(T& t)
{
  t.serialize()
}
Run Code Online (Sandbox Code Playgroud)

然后根据你的例子。

Derivied d;
serialize_object(d);
Run Code Online (Sandbox Code Playgroud)

最大的好处是您无需在此处添加运行时强制转换。如果您传递一个没有方法的对象,编译器会通知您serialize

走向虚拟

如果您确实想通过虚拟接口来处理此问题,请这样做。

struct Serializable{
 virtual void serialize()=0;
 virtual ~Serializable(){}
}

class Derived : public Serializable {
  public:
   void serialize() override;
}

void Derivied::serialize()
{
 std::cout << "Yah\n";
}
Run Code Online (Sandbox Code Playgroud)

然后在你的代码中。

Derivied d;
Serializable& s = dynamic_cast<Serializable&>(d);
Run Code Online (Sandbox Code Playgroud)

然而,这里最大的问题是谁是你的基类的所有者?他们提供虚拟医生吗?如果没有,那么使用std::unique_ptrorstd::shared_ptr可能会导致您无法直接处理该接口。


Dan*_*orn 0

您不能只将基类对象强制转换为继承类。继承类中的任何成员都不会被创建和初始化。您需要从继承类的对象开始。

当然,您可以采用另一种方式,从从基类继承的类的函数中调用基类函数,因为根据定义,基类对象将始终作为继承的类对象的一部分存在。

如果您有一个指向基类的指针,并且使用 RTTI 进行构建,则可以使用dynamic_cast 来转换为继承的类,但如果该对象不属于您尝试转换为的类,则该转换将失败并返回 NULL 。但通常调用虚函数比使用dynamic_cast更好。

  • 如果要使用“dynamic_cast”,则需要一些虚函数,请参阅[常见问题解答:为什么dynamic_cast仅在类至少有1个虚方法时才起作用?](http://stackoverflow.com/questions/4227328/常见问题解答-为什么动态强制转换仅在类具有至少 1 个虚拟方法的情况下才起作用)。 (2认同)