我想在不改变现有类的情况下添加额外的功能。
说,
class base{
public:
int i;
base(){i = 1;}
virtual void do_work(){ //Do some work}
};
如果我想向其添加serialization
成员函数,我将只创建一个派生类
class derived:public base{
public:
void serialize();
};
void derived::serialize(){
cout << "derived class" << endl;
}
我确实需要处理现有的base
个对象,例如
int main(){
base a;
derived & b = static_cast<derived &>(a);
b.serialize();
}
此示例运行没有问题。但我知道downcast
到static_cast
是一般要避免的事情。
但是我想知道这个特定用例的downcast
是否可以被认为是安全的,因为derived
类只有一个额外的成员函数。它是否有一些潜在的未定义行为来访问vtable
?
答案 0 :(得分:2)
如果你可以在派生类中编写序列化函数而不触及私有或受保护的成员,那么你应该简单地使它成为一个自由函数。这解决了一切。
答案 1 :(得分:1)
您延伸Base
的方式是因为您没有使用vtable
方法而未使用virtual
。可能更容易将其视为Derived has A Base
;您创建了一个包含Base
成员变量的新类。
我的建议。
模板功能
我个人会选择模板功能。您可以将所有工作保留在原始问题中,并且无需向您的班级添加virtual
次来电。
template<typename T>
void serialize_object(T& t)
{
t.serialize()
}
然后根据你的例子。
Derivied d;
serialize_object(d);
最大的好处是你不在这里添加运行时强制转换。如果传递的对象没有方法serialize
,编译器会通知您。
虚拟
如果你真的想通过虚拟界面来处理这个问题。
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);
然而,这里最关心的是谁是你基类的拥有者?他们提供虚拟dtor吗?如果没有,那么使用std::unique_ptr
或std::shared_ptr
可能会导致您无法直接处理界面。
答案 2 :(得分:0)
您不能将基类对象强制转换为继承的类。继承的类中的任何成员都不会被创建和初始化。您需要从继承类的对象开始。
当然,您可以采用另一种方式,从基类继承的类函数中调用基类函数,因为根据定义,基类对象将始终作为继承类对象的一部分存在。 / p>
如果你有一个指向基类的指针,并且使用RTTI构建,你可以使用dynamic_cast转换为继承的类,但是如果该对象不属于你所使用的类,则该转换将失败并返回NULL。重新尝试演员。但通常,调用虚函数比使用dynamic_cast更好。