繁体   English   中英

如何确保只调用一次虚拟基类上的赋值运算符?

[英]How to ensure that the assignment operator on a virtual base class is called only once?

我正在使用虚拟继承,如典型的钻石问题:

            A
(virtual) /   \ (virtual)
        B       C
          \   /
            D

我正在每个类中实现一个名为“deep_copy_from”的方法(但它也可以是赋值运算符=())。 该方法应复制类自己的属性,并将副本传播到上面的类。

问题是当我深度复制D实例时,A :: deep_copy_from方法被调用两次(并且它应该只被调用一次,因为只有一个“版本”的A)。 确保只调用一次的最佳方法是什么?

(B :: deep_copy_from和C :: deep_copy_from应该继续以相同的方式工作)。

这是一个示例代码:

class A
{
public:
    A(string const& p_a_name) : a_name(p_a_name) {
        cout << "A(a_name=\"" << p_a_name << "\")" << endl;
    }

    virtual void deep_copy_from(A const& a)
    {
        cout << "A::deep_copy_from(A(a_name=\"" << a.a_name << "\"))" << endl;
        this->a_name = a.a_name;
    }

protected:
    string a_name;
};

class B : public virtual A
{
public:
    B(string const &p_a_name, string const& p_b_name) : A(p_a_name), b_name(p_b_name) {
        cout << "B(a_name=\"" << p_a_name << "\", b_name=\"" << p_b_name << "\")" << endl;
    }

    virtual void deep_copy_from(B const& b)
    {
        cout << "B::deep_copy_from(B(a_name=\"" << b.a_name << "\", b_name=\"" << b.b_name << "\"))" << endl;
        this->A::deep_copy_from(static_cast<A const&>(b));
        this->b_name = b.b_name;
    }

protected:
    string b_name;
};

class C : public virtual A
{
public:
    C(string const &p_a_name, string const& p_c_name) : A(p_a_name), c_name(p_c_name) {
        cout << "C(a_name=\"" << p_a_name << "\", c_name=\"" << p_c_name << "\")" << endl;
    }

    virtual void deep_copy_from(C const& c)
    {
        cout << "C::deep_copy_from(C(a_name=\"" << c.a_name << "\", c_name=\"" << c.c_name << "\"))" << endl;
        this->A::deep_copy_from(static_cast<A const&>(c));
        this->c_name = c.c_name;
    }

protected:
    string c_name;
};

class D : public B, public C
{
public:
    D(string const &p_a_name, string const& p_b_name, string const& p_c_name, string const& p_d_name)
        : A(p_a_name), B(p_a_name, p_b_name), C(p_a_name, p_c_name), d_name(p_d_name)
    {
        cout << "D(a_name=\"" << p_a_name << "\", b_name=\"" << p_b_name
             << "\", c_name=\"" << p_c_name << "\", d_name=\"" << p_d_name << "\")" << endl;
    }

    virtual void deep_copy_from(D const& d)
    {
        cout << "D::deep_copy_from(D(a_name=\"" << d.a_name << "\", b_name=\"" << d.b_name
            << "\", c_name=\"" << d.c_name << "\", d_name=\"" << d.d_name << "\"))" << endl;
        this->B::deep_copy_from(static_cast<B const&>(d));
        this->C::deep_copy_from(static_cast<C const&>(d));
        this->d_name = d.d_name;
    }

protected:
    string d_name;
};

这是当前的输出:

A(a_name="A")
B(a_name="A", b_name="B")
C(a_name="A", c_name="C")
D(a_name="A", b_name="B", c_name="C", d_name="D")
D::deep_copy_from(D(a_name="A", b_name="B", c_name="C", d_name="D"))
B::deep_copy_from(B(a_name="A", b_name="B"))
A::deep_copy_from(A(a_name="A"))
C::deep_copy_from(C(a_name="A", c_name="C"))
A::deep_copy_from(A(a_name="A"))

更新:

目前的版本现在是:

class A
{
public:
    A(string const& p_a_name) : a_name(p_a_name) {
        cout << "A(a_name=\"" << p_a_name << "\")" << endl;
    }

    virtual void deep_copy_from(A const& a)
    {
        cout << "A::deep_copy_from(A(a_name=\"" << a.a_name << "\"))" << endl;
        this->a_name = a.a_name;
    }

protected:
    string a_name;
};

class B : public virtual A
{
public:
    B(string const &p_a_name, string const& p_b_name) : A(p_a_name), b_name(p_b_name) {
        cout << "B(a_name=\"" << p_a_name << "\", b_name=\"" << p_b_name << "\")" << endl;
    }

    virtual void deep_copy_from(B const& b)
    {
        cout << "B::deep_copy_from(B(a_name=\"" << b.a_name << "\", b_name=\"" << b.b_name << "\"))" << endl;
        this->A::deep_copy_from(static_cast<A const&>(b));
        this->deep_copy_my_bits_from(b);
    }

protected:
    void deep_copy_my_bits_from(B const& b) {
        cout << "B::deep_copy_my_bits_from(B(a_name=\"" << b.a_name << "\", b_name=\"" << b.b_name << "\"))" << endl;
        this->b_name = b.b_name;
    }

protected:
    string b_name;
};

class C : public virtual A
{
public:
    C(string const &p_a_name, string const& p_c_name) : A(p_a_name), c_name(p_c_name) {
        cout << "C(a_name=\"" << p_a_name << "\", c_name=\"" << p_c_name << "\")" << endl;
    }

    virtual void deep_copy_from(C const& c)
    {
        cout << "C::deep_copy_from(C(a_name=\"" << c.a_name << "\", c_name=\"" << c.c_name << "\"))" << endl;
        this->A::deep_copy_from(static_cast<A const&>(c));
        this->deep_copy_my_bits_from(c);
    }

protected:
    void deep_copy_my_bits_from(C const& c) {
        cout << "C::deep_copy_my_bits_from(C(a_name=\"" << c.a_name << "\", c_name=\"" << c.c_name << "\"))" << endl;
        this->c_name = c.c_name;
    }

protected:
    string c_name;
};

class D : public B, public C
{
public:
    D(string const &p_a_name, string const& p_b_name, string const& p_c_name, string const& p_d_name)
        : A(p_a_name), B(p_a_name, p_b_name), C(p_a_name, p_c_name), d_name(p_d_name)
    {
        cout << "D(a_name=\"" << p_a_name << "\", b_name=\"" << p_b_name
             << "\", c_name=\"" << p_c_name << "\", d_name=\"" << p_d_name << "\")" << endl;
    }

    virtual void deep_copy_from(D const& d)
    {
        cout << "D::deep_copy_from(D(a_name=\"" << d.a_name << "\", b_name=\"" << d.b_name
            << "\", c_name=\"" << d.c_name << "\", d_name=\"" << d.d_name << "\"))" << endl;
        this->A::deep_copy_from(static_cast<A const&>(d));
        this->B::deep_copy_my_bits_from(static_cast<B const&>(d));
        this->C::deep_copy_my_bits_from(static_cast<C const&>(d));
        this->d_name = d.d_name;
    }

protected:
    string d_name;
};

输出是:

A(a_name="A")
B(a_name="A", b_name="B")
C(a_name="A", c_name="C")
D(a_name="A", b_name="B", c_name="C", d_name="D")
D::deep_copy_from(D(a_name="A", b_name="B", c_name="C", d_name="D"))
A::deep_copy_from(A(a_name="A"))
B::deep_copy_my_bits_from(B(a_name="A", b_name="B"))
C::deep_copy_my_bits_from(C(a_name="A", c_name="C"))

我能得到比这更好的东西吗? (即更自动化)

@Alf对于任务是正确的:任务被搞砸了。 原因是它是一个二元操作,由于协方差问题,不可能在OO框架中调度二进制操作。

现在,您的问题有一个通用答案,但首先您需要了解两件事。 首先,虚拟基础总是公开的,无论你声明什么,无论标准说什么:标准都是错误的。 [证明:只需派生另一个类并再次声明任何虚拟基础公共虚拟,并且您有权访问]

第二个事实是虚拟基础是它们间接基础的每个类别的直接基础。 再次,忽略标准,因为它是错误的。 往上看。

鉴于这两个事实,很容易看到正确的模式,以避免重复:

这是你的钻石:

struct A { cp(){ "A" } virtual CP(){ cp(); } };
struct B : virtual A { cp(){ "B" } CP() { cp(); A::CP(); } };
struct C : ... ibid ...
struct D : B, C, virtual A { 
   cp() { "D"; B::cp(); C::cp(); }
   CP() { cp(); A::cp(); }
};

为了简洁,我放弃了返回类型和其他东西。 cp()函数通过首先处理任何成员然后调用每个非虚拟基础来处理其成员(递归地)来向下钻取。 实际上它应该受到保护,因为它不适合公共客户。 向下钻取是强制性的,因为您无法自己访问间接非虚拟基础,只能直接访问。

CP()函数是虚拟的,因此无论您使用哪个指针(A,B,C或D),任何调用都会转到完整对象的唯一CP。

它通过调用自己的类的cp()处理所有成员和非虚拟基础子对象成员,然后处理虚拟基础,在这种情况下只有一个,即A.

如果X :: CP()成为

X *X::clone() const;

然后,如果你可以从任何指针克隆完整的对象并返回相同的动态和静态类型:如果你的动态类型是D而静态类型是B,你将得到一个B *到D对象,就像你开始时一样。

不可能以这种方式进行分配。 根本不可能完成作业。 原因是赋值在两个参数上是协变的。 无法确保源和目标具有相同的动态类型,这是分配工作所必需的。 如果源太大,其中一些会被切掉。 更糟糕的是,如果目标太大,其中一些永远不会被分配给。 因此,您调度的对象(目标或源)没有区别:它无法正常工作。 唯一可以工作的分配是基于静态类型的非虚拟分配。 这也可以在片段之上或之下,但至少这个问题是非常明显的。

克隆有效,因为它是一个只有一个参数的函数(即自我对象)。 通常,如果你使用“对象东西”而不是“有价值的东西”那么,因为你只能真正操纵值,你必须使用指针。 在这种情况下,clone()和朋友就是你想要的:你可以指定一个指针就好了!

有两个问题:一个是关于双重复制到A部分,另一个是关于虚拟赋值操作。

虚拟分配:不是一个好主意,因为它将错误检测从编译时间转移到运行时。 根本就不要。 似乎需要虚拟分配(或类似于分配的操作)的一般解决方案是实现克隆,即生成动态分配副本的虚拟clone成员函数。

双重复制:简单的答案是在结构方面表达任务。 这样做的惯用方法被称为“交换习语”。 简单地说, 构造一个副本,然后其内容与当前实例交换 ,然后让你构造的实例的析构函数进行清理。

干杯&hth。,

deep_copy_from不是共变体,您只能在返回类型中使用协方差。

您可能会使用您编写的代码获得“过载隐藏虚拟功能”警告。

因为在没有调用A版本的情况下无法调用B或C版本,所以除非您修改B或C,否则如果必须同时调用B和C版本,则无法避免A版本被调用两次。

鉴于B和C都从A继承虚拟,你可能不应该让它们调用A版本,因为最终的类负责A部分。

暂无
暂无

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

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