简体   繁体   English

从成员成语中复制/移动构造函数

[英]Copy/move constructor for base-from-member idiom

I'm using base-from-member idiom and I now stuck with copy/move constructors for them. 我使用的是成语基础成语,现在我为它们使用了复制/移动构造函数。 Suppose following code: 假设以下代码:

#include <iostream>
#include <string>
#include <boost/lexical_cast.hpp>

using namespace std;

struct A // base class
{
    A(string &s) : s(s), c(0) { };
    A(const A &a) : s(a.s), c(a.c) { };
    void print() { cout << s << endl; c++; }
    int print_count() { return c; }

    string &s;
    int c;
};

struct B_base // this class will be initialized before A
{
    B_base(int i)
    {
        s = boost::lexical_cast<string>(i);
    }

    B_base(const B_base &other) : s(other.s) { };

    string s;
};

struct B : B_base, A // main class
{
    B(int i) : B_base(i), A(B_base::s) { }
    B(const B &other) : B_base(other), A(other) { } // <-- problem here 

    using A::print;
    using A::print_count;
};


int main()
{
    B b(10);
    b.print(); // prints '10'
    cout << b.print_count() << endl; // prints '1'


    B b1(b);
    b1.print(); // prints '10'

    A &a = b;
    a.s =  "FAIL"; // we modify b, not b1 here!

    b1.print(); // but b1 prints 'FAIL' here --- error (it should still print '10')
    cout << b.print_count() << " " << b1.print_count() << endl; // prints '1 3'

    return 0;
}

Problem here is that reference As (which is point to B_base::s ) is copied from one instance to another, while it should be modified to point to another B_base::s . 这里的问题是,引用As (指向B_base::s )从一个实例复制到另一个实例,而应该对其进行修改以指向另一个B_base::s Things may be even worse, if previous instance is go out of scope ending with dangling references. 如果以前的实例超出了以悬挂引用结尾的范围,情况可能会变得更糟。

My question is: how can I make correct copy of class with base-from-member idiom? 我的问题是:我怎样才能使用base-from-member成语来正确复制类? (I think move constructor will be similar to copy one, right?) (我认为move构造函数将类似于复制一个,对吧?)

The base-from-member idiom you are exercising in this case means: you want a class B derived from A with have to be initialized using a member of B (with is: string s ). 在这种情况下,您正在使用的“从成员开始”成语意味着:您想要从A派生的class B必须使用B的成员(with是: string s )进行初始化。

B b(10);
B b1(b); //   B(const B &other) : B_base(other), A(other) { }
         //   now A::s in b1 is a ref to b.s
A &a = b;//   and a.s is a ref to b.s too.
a.s =  "FAIL"; // we modify b, and A::s in b1 to!

This problem can be solved making the copy constructor: 使用复制构造函数可以解决此问题:

B(const B &other) : B_base(other), A(B_base::s) { }

Also, having A::s and B_base::s with the same name, make thing more difficult to understand. 同样,具有相同名称的A::sB_base::s使事情变得更难以理解。

EDIT: As a class designer, you have to decide with is the exact meaning of your copy constructor. 编辑:作为一个类设计器,您必须决定与您的复制构造函数的确切含义。
For example, in this case you may want to keep track (with A::c ) of the number of printing of each newly create object A . 例如,在这种情况下,您可能希望(使用A::c )跟踪每个新创建的对象A的打印数量。 The copy constructor I proposed do it. 我建议的复制构造函数可以做到这一点。

But if you want to keep track of all printing of the original string thing are more complex. 但是,如果您要跟踪原始字符串的所有打印,则事情会更加复杂。 Just note that if you copy the old A::c to the new A it will be correct initialized, bur not cross actualized when the the printing of the same original string is made using different copies of A . 只需注意,如果将旧的A::c复制到新的A ,它将被正确初始化,当使用不同的A副本打印相同的原始字符串时,bur不会交叉实现。 If this is not a problem you can modify the constructors: 如果这不是问题,则可以修改构造函数:

A(string &s, int _c=0) : s(s), c(_c) { };

... ...

B(const B &other) : B_base(other), A(B_base::s, other.c) { }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM