C ++,std :: list,赋值,继承

时间:2016-04-16 22:38:10

标签: c++ inheritance assignment-operator stdlist

class A, B;
class A {
    public:
        A& operator= ( const A &rhs ) { return *this; }
};
class B: public A {
    public:
        B& operator= ( const A &rhs ) { return *this; }
};
A a;
B b;
std::list < A > aa;
std::list < B > bb;
a = b; // works
b = a; // works
// aa = bb; // fails
// bb = aa; // fails

如何让bb = aa工作?

5 个答案:

答案 0 :(得分:6)

您在此处遗漏的是,即使AB是相关类型,std::list<A>std::list<B>实际上是不相关的类型(除了两者都说list)。因此,您无法使用复制分配在它们之间进行分配。

但是,假设您可以使用其分配运算符为彼此分配类型AB,则可以使用list&#39; s {{ 1}}复制迭代器范围的方法:

assign

答案 1 :(得分:4)

您可以使用copyback_inserter

执行此操作
std::copy(aa.begin(), aa.end(), back_inserter<list<B>>(bb));

但是在可以从源元素(这里是A)构造目标元素(这里是B)的条件下。所以在这里,你需要一个基于A对象的B构造函数。

Online demo

注意:如果您没有在目标类中拥有复制所需的构造函数,但是您还有其他方法可以从源构建目标对象,则可以考虑使用std::transform()

顺便提一下,注意:a=b有效,但可能会导致slicing

答案 2 :(得分:3)

您可以将mySring = "abc==abc++abc==bc++abc"; String[] splitString = myString.split("\\W+"); 类型的对象分配给ParseQuery query = new ParseQuery("Child"); query.fromLocalDatastore(); query.findInBackground(new FindCallback<ParseObject>() { @Override public void done(List<ParseObject> objects, ParseException e) { if (e == null) { removeAllViews(pager); children.clear(); //Clear it out before we regen every person! for (int i = 0; i < objects.size(); i++) { ChildInfo child = new ChildInfo(); child.name = objects.get(i).getString("Name"); child.gradeLevel = objects.get(i).getString("GradeLevel"); child.gradeLevelInt = objects.get(i).getInt("GradeLevelInt"); children.add(child); } Log.i("HomePagerAdapter", "Children Size: " + children.size() + "\n Obj Size: " + objects.size()); for (int i = 0; i < children.size(); i++) { addChild(pager, children.get(i).name, children.get(i).gradeLevelInt); } } else { Log.e("HomePagerAdapter", e.toString()); } } });类型的对象,但这并不代表AB的保留。

而不是你可以使用list<A>

list<B>

编辑:为了使用它,您必须先调用std::copy,或者更好地使用@Christophe所述的std::copy(bb.begin(), bb.end(), std::back_inserter(aa)); // instead of aa = bb

你应该清楚你在这里做了什么:它要么切片(aa.resize(bb.size()))要么指定一个非最终类(back_inserter)。为了避免这种情况,您应该使用指针并使用克隆模式。

答案 3 :(得分:2)

就编译器而言std::list<A>std::list<B>是不相交的类型。如果您认为std::list已在内部为A个对象分配内存,则这是有意义的。试图将B个对象分配到该空间可能很灾难。

想象一下,例如,B有一个额外的属性。现在,如果您尝试将B存储到足够A的内存中,则可能不合适。可以使用类似的逻辑来查看另一个方向也失败的原因:如果将A存储到B的空间中,编译器会期望它所信任的B的额外属性在那个空间是有效的。如果你分配了一个A,那个空间里面有谁知道什么。

如果您希望此分配能够工作,您将需要使用某种形式的间接。例如,您可以使用两个std::list<A*>个实例或两个std::list<std::shared_ptr<A>>个实例。这可行,因为B* 可以安全地视为A*,至少假设这些类已正确编写。

答案 4 :(得分:1)

我认为没有人真正试图回答如何分配bb = aa;的问题

如前所述,您不能将std::list<B>的隐式强制转换或赋值运算符定义为自由运算符。但你有两个选择。他们都依赖于对这个集合进行子类化......只要你不允许任何其他状态就可以了。

选项#1,将BB定义为std::list<B>的子类,bb将使用这些类。 (BB将获得一个额外的赋值运算符。)

选项#2,是使用辅助类,并且可能更接近您的原始意图。辅助类将定义为上述BB类,将隐式转换运算符添加回std::list<B>

完整的例子如下:

class A {};

class B: public A {
public:
    B() = default;
    B( const A &rhs ) {} // Empty because A and B are not defined with any state.
    B& operator= ( const A &rhs ) { return *this; }
};

class BB : public std::list<B> {
public:
    BB() = default;
    BB(const std::list<A> &aa) { assign( aa.begin(), aa.end() ); }
    BB& operator= ( const std::list<A> &rhs ) { assign(rhs.begin(), rhs.end()); return *this; }
    operator std::list<B>() { return *this; }
};
// No new member variables or virtual methods are allowed.
static_assert( sizeof (std::list<B>) == sizeof (BB), "Bad derivation of std::list<B>" );


A a;
B b;

b = a; // works

std::list<A> aa;
std::list<B> bb;

BB helper;
bb = helper = aa;  // Option #2; bb is std::list<B>

或者您可以直接使用BB

BB bb = aa;        // Option #1; use bb just like std::list<B>