正在阻止复制构造函数中的切片
Preventing slicing in copy constructor
我想复制一个Foo对象类型的向量,但这些对象可以是几种不同的Foo派生类型。我不知道如何在不切片的情况下进行复制。这是我的玩具代码
#include "stdafx.h"
#include <memory>
#include <vector>
#include <string>
#include <iostream>
class Foo
{
public:
Foo() { m_x = "abc"; }
Foo( const Foo &other ) { m_x = other.m_x; }
virtual std::string ToString() { return m_x; }
std::string m_x;
};
class FooDerivedA : public Foo
{
public:
FooDerivedA() : Foo() { m_y = 123; }
std::string ToString() { return m_x + ", " + std::to_string( m_y ); }
int m_y;
};
class FooDerivedB : public Foo
{
public:
FooDerivedB() : Foo() { m_z = true; }
std::string ToString() { return m_x + ", " + std::to_string( m_z ); }
bool m_z;
};
class Foos
{
public:
Foos(){}
Foos( const Foos &other )
{
for ( auto &foo : other.m_Foos )
{
// I believe this is slicing. How can I prevent this?
auto f = std::unique_ptr<Foo>( new Foo( *foo ) );
m_Foos.push_back( std::move( f ) );
}
}
void Add( std::unique_ptr<Foo> foo ) { m_Foos.push_back( std::move( foo ) ); }
std::string ToString()
{
std::string s;
for ( auto &foo : m_Foos )
{
s += foo->ToString() + "n";
}
return s;
}
private:
std::vector<std::unique_ptr<Foo>> m_Foos;
};
int main()
{
Foos f1;
f1.Add( std::unique_ptr<FooDerivedA>( new FooDerivedA ) );
auto f2 = Foos( f1 );
std::cout << "f1:" << f1.ToString() << std::endl;
std::cout << "f2:" << f2.ToString() << std::endl;
system("pause");
return 0;
}
我不能指定类型应该是FooDerivedAlike:
auto f = std::unique_ptr<Foo>( new FooDerivedA( *foo ) );
因为它可能是FooDerivedB。如何在不进行切片的情况下复制数据?
解决此问题的经典方法是实现virtual Foo *clone() const
,然后调用它而不是复制构造函数。
因此,如果我们在x
中有一个Foo
(派生形式)的对象,我们可以通过以下方式创建另一个对象:
void someFunc(Foo *x)
{
Foo *copy_of_x = x->clone();
...
delete copy_of_x; // Important so we don't leak!
}
注意,由于它是一个虚拟函数,我们不能在foo
的构造函数或它的任何派生类型中调用它,因为虚拟函数在构造函数中不能"正确"操作。
您可以考虑在容器中使用Boost.Variant而不是指针。这样可以避免很多切片和内存管理问题。此外,您还可以从默认构造函数中获得更多。
以下是使用此设计对您的示例进行的全面返工:
#include <vector>
#include <iterator>
#include <string>
#include <boost/variant.hpp>
struct Foo
{
Foo() : m_x("abc") {}
std::string m_x;
};
struct FooDerivedA : Foo
{
FooDerivedA() : m_y(123) {}
int m_y;
};
struct FooDerivedB : Foo
{
FooDerivedB() : m_z(true) {}
bool m_z;
};
typedef boost::variant<FooDerivedA, FooDerivedB> a_foo;
struct to_string : boost::static_visitor<std::string>
{
std::string operator()(Foo const& foo) const
{return foo.m_x;}
std::string operator()(FooDerivedA const& foo) const
{return foo.m_x + ", " + std::to_string(foo.m_y);}
std::string operator()(FooDerivedB const& foo) const
{return foo.m_x + ", " + std::to_string(foo.m_z);}
};
std::ostream& operator<<(std::ostream& os, a_foo const& foo)
{
return os << boost::apply_visitor(to_string(), foo);
}
int main()
{
std::vector<a_foo> f1;
f1.push_back(FooDerivedA());
f1.push_back(FooDerivedB());
auto f2 = f1;
std::ostream_iterator<a_foo> out_it(std::cout, "n");
std::cout << "f1:" << std::endl;
std::copy(f1.begin(), f1.end(), out_it);
std::cout << "f2:" << std::endl;
std::copy(f2.begin(), f2.end(), out_it);
return 0;
}
相关文章:
- "error: no matching function for call to"构造函数错误
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 为什么在没有显式默认构造函数的情况下,将另一个结构封装在联合中作为成员的结构不能编译
- 为什么在C++中使用私有复制构造函数与删除复制构造函数
- 选择要调用的构造函数
- 如何委托派生类使用其父构造函数?
- 构造函数正在调用一个使用当前类类型的函数
- 没有用于初始化C++中的变量模板的匹配构造函数
- 初始化具有非默认构造函数的std::数组项的更好方法
- 当从函数参数中的临时值调用复制构造函数时
- 在c++构造函数中使用随机字符串生成器
- 一对向量构造函数:初始值设定项列表与显式构造
- 从构造函数抛出异常时如何克服内存泄漏
- 我不明白为什么我声明一个空的内部结构并将其传递给构造函数
- 继承:构造函数,初始化C++11中基类的类C数组成员
- 具有默认模板类型的默认构造函数的类型推导
- 缺少复制构造函数与对象切片有何关系
- 正在阻止复制构造函数中的切片
- 什么是隐藏切片复制构造函数