首页 \ 问答 \ 仅使用基类指针复制派生实体,(没有详尽的测试!) - C ++(Copying derived entities using only base class pointers, (without exhaustive testing!) - C++)

仅使用基类指针复制派生实体,(没有详尽的测试!) - C ++(Copying derived entities using only base class pointers, (without exhaustive testing!) - C++)

给定一个由许多派生类继承的基类,以及一个程序结构,它要求您通过基类指针来管理每个实体。 当只有基类指针已知时,是否有一种简单的方法来复制整个派生对象?

环顾它看起来可能(如果令人难以置信的话)使用dynamic_cast调用来检查基指针是否可以转换为适当的派生类,然后使用派生类的拷贝构造函数复制它。 然而,这并不是一个真正的最佳解决方案,部分原因是过度使用dynamic_cast,而且它会让整个维护和扩展头疼。

我遇到的另一个更优雅的解决方案如下:

class Base
{
public:
   Base(const Base& other);
   virtual Base* getCopy();
   ...
}

class Derived :public Base
{
   Derived(const Derived& other);
   virtual Base* getCopy();
   ...
}

Base* Base::getCopy()
{
   return new Base(*this));
}

Base* Derived::getCopy()
{
   return static_cast<Base*>(new Derived(*this));
}

然后,通过调用基类指针上的getCopy()指向任何派生对象,仍然会得到一个基类指针,但是整个派生对象也已被复制。 这个方法感觉更容易维护,因为它只需要在所有派生类中使用类似的getCopy()函数,并且不再需要针对所有可能的派生对象进行测试。

本质上,这是明智的吗? 还是有更好的,甚至更干净的方式呢?


Given a base class that is inherited by plethora of derived classes, and a program structure that requires you manage these via base class pointers to each entity. Is there a simple way to copy the entire derived object when only the base class pointer is known?

Looking around it would seem possible (if incredibly tedious) to use the dynamic_cast call to check if a base pointer can be cast as the appropriate derived class, then copy it using the derived class's copy constructor. However this is not really an optimal solution partly due to the excessive use of dynamic_cast and also it would see a total headache to maintain and extend.

Another more elegant solution I have come across is as follows:

class Base
{
public:
   Base(const Base& other);
   virtual Base* getCopy();
   ...
}

class Derived :public Base
{
   Derived(const Derived& other);
   virtual Base* getCopy();
   ...
}

Base* Base::getCopy()
{
   return new Base(*this));
}

Base* Derived::getCopy()
{
   return static_cast<Base*>(new Derived(*this));
}

Then by calling getCopy() on the Base class pointer to any derived object one still gets a base class pointer back but also the whole of the derived object has been copied. This method feels a lot more maintainable as it just requires a similar getCopy() function to be in all derived classes, and does away with the need to test against all possible derived objects.

Essentially, is this wise? or is there a better, even neater way of doing this?


原文:https://stackoverflow.com/questions/5027456
更新时间:2019-06-23 01:16

最满意答案

这种方法是复制多态对象的首选方式,因为它减轻了确定如何将任意类型的对象复制到该对象的责任,而不是在编译时尝试确定它。 更一般地说,如果你不知道在编译时基类指针指向什么,你就不可能知道为了得到正确的副本而需要执行的许多潜在代码段中的哪一段。 因此,任何工作解决方案都需要动态选择代码,而虚拟功能是实现这一目标的好方法。

对你的实际代码有两点评论。 首先,C ++继承允许派生类重写基类成员函数,以使派生函数返回比基类版本更具体的类型的指针。 这被称为协变性。 作为一个例子,如果一个基类函数是

virtual Base* clone() const;

然后派生类可以将其覆盖为

virtual Derived* clone() const;

这将工作得很好。 例如,这可以让你拥有这样的代码:

Derived* d = // something...
Derived* copy = d->clone();

其中,没有协变超载,将不合法。

另一个细节 - 在你的代码中,你明确地static_cast派生指针到你的代码中的基指针。 这是完全合法的,但没有必要。 C ++会隐式地将派生类指针转换为基类指针而不需要转换。 但是,如果您使用协变返回类型的想法,这将不会出现,因为返回类型将匹配您将创建的对象的类型。


This approach is the preferred way of copying polymorphic objects because it offloads the responsibility of determining how to copy an object of an arbitrary type to that object, rather than trying to determine it at compile-time. More generally, if you don't know what the base class pointer points at at compile-time, you can't possibly know which of the many potential pieces of code you would need to execute in order to get a correct copy. Because of this, any working solution will need a dynamic selection of code, and the virtual function is a good way to do this.

Two comments on your actual code. First, C++ inheritance allows a derived class overriding a base class member function to have the derived function return a pointer of a type more specific than the base class version. This is called covariance. As an example, if a base class function is

virtual Base* clone() const;

Then a derived class can override it as

virtual Derived* clone() const;

And this will work perfectly fine. This allows you, for example, to have code like this:

Derived* d = // something...
Derived* copy = d->clone();

Which, without the covariant overload, wouldn't be legal.

Another detail - in the code you have, you explicitly static_cast the derived pointers to base pointers in your code. This is perfectly legal, but it's not necessary. C++ will implicitly convert derived class pointers to base class pointers without a cast. If, however, you use the covariant return type idea, this won't come up because the return type will match the type of the objects you'll be creating.

2014-08-11

相关问答

更多

c ++多态,派生类的名称解析(c++ polymorphism, name resolution for derived class)

不同类中的方法不会一起重载; 在Derived定义另一个f()可以防止在重载过程中考虑Base那个。 如果要添加新的重载而不隐藏基类中定义的重载,则需要将基本定义显式引入派生类。 public: using Base::f; Methods in different classes do not overload together; defining another f() in Derived prevents the one in Base from being considered ...

C ++:比较基类和派生类的指针(C++: Comparing pointers of base and derived classes)

如果你想比较任意的类层次结构,安全的选择是使它们变为多态并使用dynamic_cast class Base { virtual ~Base() { } }; class Derived : public Base { }; Derived* d = new Derived; Base* b = dynamic_cast<Base*>(d); // When comparing the two pointers should I cast them // to the same ...

在C ++中使用struct作为派生类的基础(Use struct as base for derived class in C++)

你只是从C结构派生。 在C ++中, struct和class之间的唯一区别是后者的默认成员可访问性是private ,而前者是public 。 如果只涉及单一继承,那么class的地址应该与作为基类的struct相同。 如果继承仅用于实现(即两者之间不存在Is-A关系),请考虑使用私有继承。 You just derive from the C struct. In C++, the only difference between a struct and a class is that the ...

派生类'复制构造函数(C ++)初始化列表的基类(Base class on the initialisation list of a derived class' copy constructor (C++))

这是否真的必须在Derived的复制构造函数的初始化列表中使用(隐式或显式)Base(默认)构造函数,并且只在Derived的复制构造函数的主体中调用Base的复制构造函数,当实际存在对象时可以通过Base的复制构造函数附加吗? 为什么你想要这样做? (哦,你不能从派生类的构造函数体中调用基类的复制构造函数。只能从它的初始化列表中调用。) 否则 - (* this)是一个有效的对象? 基础初始化列表完成的那一刻,所有基础成员(和基类)都是完全构造的。 但是,类本身只在构造函数完成时才完全构造。 更 ...

指向派生类对象的C ++基类指针不调用派生的相等运算符函数(C++ Base class pointer pointing to derived class object doesn't call derived equal operator function)

要使虚函数处理派生类,它必须具有与基类相同的签名。 所以你的operator==()必须采用const Movie & argument。 我没有尝试过,但是我试图让你的比赛更具体的是使用动态强制转换。 接下来会发生什么。 // The "override" clause makes sure that the virtual function signature matches the one in the base class bool FunnyMovie::operator==(const ...

c ++派生类问题(c++ derived class question)

它是私有派生的,应该为每个基类分别声明继承方法,如果不是,那么它默认是私有的。 It's private derived, inheritance method should be declared for each base class individually, if not, then it's private by default.

在C ++中将指针转换为前向声明的类到其真正的基类是否安全?(Safe to cast pointer to a forward-declared class to its true base class in C++?)

它可能有效,但风险很大。 问题在于Derived*和Base*大部分时间确实在引擎盖下有相同的值(可以打印)。 然而,只要你有虚拟继承和多重继承,这是不正确的,并且当然不能被标准保证。 当使用static_cast ,编译器执行必要的算术(因为它知道类的布局)来调整指针值。 但是这种调整不是由reinterpret_cast或C风格演员执行的。 现在,您可以完美地重写代码,如下所示: // foo.h class Derived; class Foo { public: void someM ...

来自C ++中不同基类的Ambigious函数(Ambigious functions from different base classes in C++)

跨类边界不允许函数重载。 您可以通过编写Derived类来解决此问题 - class Derived : public Base1, public Base2 { public: using Base1::go; using Base2::go; }; Function overloading is not allowed across class boundaries. You can fix this by writing the Derived class like so ...

相关文章

更多

最新问答

更多
  • Android宽度:100%修复(网站接管问题)(Android width:100% fix (website takeover issue))
  • C ++函数/方法设计的良好实践(Good practice in C++ function/method design)
  • 计算其他表中不存在的所有记录 - SQL查询(Count all records that does not exist to other table - SQL Query)
  • 为什么我要用JPA共享ID?(Why do I get shared Ids with JPA?)
  • asp.net - 如何显示来自html格式的数据行的字段(asp.net - how to display a field from data row that is in html format)
  • 我们如何使用ActiveRecord从连接表中删除行?(How can we delete rows from a join table by using ActiveRecord?)
  • ng-class搞乱了类的顺序(ng-class messing with the order of classes)
  • oracle 12g无效数字错误(oracle 12g invalid number error)
  • 更改ng-src值onclick(Change ng-src value onclick)
  • 如何在android中自动添加自定义依赖项以创建新项目?(How to add custom dependencies automatically in android for ever a new project is created?)
  • datetime函数在PHP中(datetime function in php)
  • 在javascript中获取会话数组的值(in javascript get the value of a session array)
  • 如何在UTF8中编译LaTeX?(How can I compile LaTeX in UTF8? [closed])
  • Rspec:“array.should == another_array”,但不用担心订单(Rspec: “array.should == another_array” but without concern for order)
  • Logcat错误:无法在android片段中加载视图(Logcat error: unable to load view in android fragments)
  • JavaFX的。(JavaFX. Adding items to the list in different threads is not working)
  • 从GDATA日历资源迁移到Google Calendar Resource api(Migrate from GDATA calendar resource to Google Calendar Resource api)
  • SSRS 2008 - 以零情景处理分割(SSRS 2008 - Dealing with division by zero scenarios)
  • 我如何以编程方式添加一个listView列标题的点击事件(How can I add a listView column header a click event programmatically)
  • Wxpython:无法检索有关列表控件项XXX的信息(Wxpython: Couldn't retrieve information about list control item XXX)
  • 使用Tortoise SVN在SVN存储库中移动目录(Move Directory across SVN repository using Tortoise SVN)
  • 天蓝色服务结构集群中的web api无状态服务是否在一段时间不活动后进入休眠状态?(Do web api stateless services in azure service fabric cluster go to sleep after a period of inactivity?)
  • 我可以设置intelliJ来突出显示PHP编码风格吗?(Can I set intelliJ to highlight php coding style?)
  • 用javafx创建一个Truetype字体文件(Creating a Truetype Font file with javafx)
  • Spring ftp配置错误(Spring ftp configuration is wrong)
  • 使用gsub去除多个字符(Using gsub to strip multiple characters)
  • 续订推送证书并保持当前的App Store App正常工作(Renew Push certificate and keep current App Store App working)
  • js:ES5和ES6之间关于'this'关键字用法的一个令人困惑的观点(js: one confusing point about 'this' keyword usage between ES5 and ES6)
  • window.onload vs $(document).ready()(window.onload vs $(document).ready())
  • 在Swift中,如何声明一个符合一个或多个协议的特定类型的变量?(In Swift, how can I declare a variable of a specific type that conforms to one or more protocols?)