C++ 扩展现有的C++;班

C++ 扩展现有的C++;班,c++,inheritance,downcast,C++,Inheritance,Downcast,我想在不更改现有类的情况下添加额外的功能 说 如果我想向它添加序列化成员函数,我只需要创建一个派生类 class derived:public base{ public: void serialize(); }; void derived::serialize(){ cout << "derived class" << endl; } 这个例子运行起来没有问题。但我确实知道,通过static\u cast的downcast通常是需要避免的 但是我想知道

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

如果我想向它添加
序列化
成员函数,我只需要创建一个派生类

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

void derived::serialize(){
    cout << "derived class" << endl;
}
这个例子运行起来没有问题。但我确实知道,通过
static\u cast
downcast
通常是需要避免的


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

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

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


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

扩展
Base
的方式没有使用
vtable
,因为没有
方法。可以更容易地将其视为
派生有一个基础
;您创建了一个包含
Base
成员变量的新类

我的建议

模板功能

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

template<typename T>
void serialize_object(T& t)
{
  t.serialize()
}
最大的好处是您没有在这里添加运行时强制转换。如果传递的对象没有方法
序列化
,编译器将通知您

虚拟化

如果您真的想通过虚拟接口来处理这个问题,那么就这样做

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

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

void Derivied::serialize()
{
 std::cout << "Yah\n";
}
struct可序列化{
虚拟空序列化()=0;
虚拟~Serializable(){}
}
派生类:可公开序列化{
公众:
void serialize()重写;
}
void Derivied::serialize()
{

std::cout如果您可以在派生类中编写序列化函数而不涉及私有或受保护的成员,那么您应该简单地将其设置为自由函数。这解决了所有问题。

您在说什么
vtable
呢?我没有看到任何虚拟函数。而且,
派生的
基本
,而不是相反,但您正在铸造一个
(即,
基本
类型)对于
派生的
类型…我看到的问题是,我们不知道基类是否有虚拟dtor。这可能会导致在处理堆上的对象时出现问题。我会制作一个模板函数来处理这个问题。这样,如果传递不支持序列化方法的对象,就会收到编译时警告。@JamesAdkison,virtual函数按我最初的意思添加回来。情况是我有另一个程序创建的
base
对象,它不知道
派生的
。我之所以向下转换
base
是因为我需要用
派生的
中添加的新
函数对其进行序列化。如果要继续,您需要一些虚拟函数要使用
dynamic\u cast
,请参阅。在我的应用程序中,还有从
base
继承的其他派生类。我需要对它们执行相同的序列化。所有这些派生对象都存储为
base*
,因此free函数无法实现作为成员函数的多态函数调用((即
obj.serialize()
)。为什么要将
派生的
强制转换为
可序列化的
?不是
序列化()
函数已经在
派生的
中可用了吗?@MikeJiang您是对的,在这种情况下确实没有理由强制转换。在这种情况下,我更愿意编写一个通用函数来处理通用接口,如
序列化
或模板函数。
template<typename T>
void serialize_object(T& t)
{
  t.serialize()
}
Derivied d;
serialize_object(d);
struct Serializable{
 virtual void serialize()=0;
 virtual ~Serializable(){}
}

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

void Derivied::serialize()
{
 std::cout << "Yah\n";
}
Derivied d;
Serializable& s = dynamic_cast<Serializable&>(d);