不允许切片以保持多个父类属性同步

Disallow slicing to keep multiple parent class properties in sync

本文关键字:父类 属性 同步 切片 不允许      更新时间:2023-10-16

我从两个父类派生一个对象。这两个父母都有不同类型的属性,但我希望孩子能让他们保持同步。然而,我想禁止库的用户通过切片意外地将Child视为ParentAParentB。例如:

#include <iostream>
class ParentA
{
public:
    void modify()
    {
        std::cout << "modifyA" << std::endl;
    }
    void readA()
    {
        std::cout << "readA" << std::endl;
    }
};
class ParentB
{
public:
    void modify()
    {
        std::cout << "modifyB" << std::endl;
    }
    void readB()
    {
        std::cout << "readB" << std::endl;
    }
};
class Child : public ParentA, public ParentB
{
public:
    void modify()
    {
        // Do some bounds checking to make sure ParentA and ParentB stay in sync, then:
        ParentA::modify();
        ParentB::modify();
        std::cout << "modifyChild" << std::endl;
    }
};
void Change(ParentA object)
{
    object.modify();
}
int main()
{
    std::cout << "This is standard:" << std::endl;
    ParentA parentA;
    parentA.modify();
    ParentB parentB;
    parentB.modify();
    Child child;
    child.readA();
    child.readB();
    child.modify();
    std::cout << "Want to avoid this:" << std::endl;
    Change(child);
    return 0;
}

此对Change(child);的调用调用ParentAmodify()函数,其中ParentA属性可能与ParentB属性不同步,从而使Child处于坏状态。

ParentAParentB中有很多函数(这里是read*()),我不想手动从Child转发,所以我不能私下推导。

有没有办法使对Change(child)的调用产生编译器错误(而不更改Change的签名)?

实际上有一种方法可以做到这一点(尽管说你不喜欢):privateprotected继承是实现你想要的东西的C++机制。

请记住,由于您的子类试图在A和B之间保持某种不变量,如果您继承publicly,则无论如何都会有人找到使用A或B的接口来违反不变量的方法,因此您需要保护这些接口不受直接在子类中使用的影响,而限制继承完全做到了这一点。

如果父类中有一些方法不影响两个类不变量,那么可以将它们using放到Child的公共部分中。

正如注释所说,最干净的方法可能是用privateParentAParentB继承并转发所需的函数。

我有另一个想法:可以将ParentAParentB的功能提取到两个抽象类(AbstractParentAAbstractParentB)中,并将这些类用作基类。

这会给你想要的行为:

#include <iostream>
class AbstractParentA
{
    virtual void no_instance() = 0;
public:
    void modify()
    {
        std::cout << "modifyA" << std::endl;
    }
    void readA()
    {
        std::cout << "readA" << std::endl;
    }
};
class AbstractParentB
{
    virtual void no_instance() = 0;
public:
    void modify()
    {
        std::cout << "modifyB" << std::endl;
    }
    void readB()
    {
        std::cout << "readB" << std::endl;
    }
};

class ParentA : public AbstractParentA
{
    virtual void no_instance() override {}
};

class ParentB : public AbstractParentB
{
    virtual void no_instance() override {}
};
class Child : public AbstractParentA, public AbstractParentB
{
    virtual void no_instance() override {}
public:
    void modify()
    {
        // Do some bounds checking to make sure ParentA and ParentB stay in sync, then:
        AbstractParentA::modify();
        AbstractParentB::modify();
        std::cout << "modifyChild" << std::endl;
    }
};
void Change(ParentA object)
{
    object.modify();
}
int main()
{
    std::cout << "This is standard:" << std::endl;
    ParentA parentA;
    parentA.modify();
    ParentB parentB;
    parentB.modify();
    Child child;
    child.readA();
    child.readB();
    child.modify();
    std::cout << "Want to avoid this:" << std::endl;
    Change(child);
    return 0;
}

错误C2664:"void Change(ParentA)":无法从"Child"转换参数1

注意:没有用户定义的转换运算符可以执行此转换,或者该运算符不能称为