尚未建立具体课程

qua*_*ana 1 c++ c++17

我有一个这样的类层次结构:

class Base {
public:
    virtual bool foo() const = 0;
    static Base& getHeadInstance();
};

class Concrete: public Base {
public:
    explicit Concrete(Base& f): fwd(f) {}

    // ... other member functions elided
    bool foo() const override { return /* some calculation */ && fwd.foo(); }
private:
    Base& fwd;
};
Run Code Online (Sandbox Code Playgroud)

这样我就可以构造一系列这样的实例:

Concrete c1(Base::getHeadInstance());
Concrete c2(c1);
Concrete c3(c2);
Run Code Online (Sandbox Code Playgroud)

这样就c3可以做出决定,并可能要遵循c2,而后者又可以c1Chain of Responsibility模式一样遵循。

问题在于c2c3构造不正确,其fwd成员始终引用Base::getHeadInstance()

这里出了什么问题?解决方法是什么?

更新:

静态成员返回什么都无所谓。假设它返回了一个实例:

class Head: public Base {
public:
    Head() = default;
private:
    bool foo() const override { return true; }
};
Base& Base::getHeadInstance(){ static Head head; return head; }
Run Code Online (Sandbox Code Playgroud)

Max*_*hof 5

我以前也遇到过同样的问题。归结为您的自定义构造函数Derived(Base&)与隐式定义的副本构造函数的重载解析Derived(const Derived&);,其中隐式副本构造函数只是赢了。删除它并不能解决问题,它仍然参与了重载解决方案(但是它确实阻止了错误的事情无声地发生)。

这是一个简化的示例:

struct Base
{
    virtual ~Base();
};

struct Derived : Base
{
    Derived(Base&);
    Derived(const Derived&); // Implicitly or explicitly declared in any case.
};

Derived getDerived();

void test()
{
    Derived d1 = getDerived();
    Derived d2(d1); // copies
}
Run Code Online (Sandbox Code Playgroud)

https://godbolt.org/z/aoJFlC

有几种方法可以使代码按照编写方式的方式进行操作(请参阅其他答案),但是我想指出,您应该格外小心,以免代码的下一个读者你有困惑。强制转换为Base&,重用了副本构造函数的语义或类似的用法,Derived(Base*);都会在未来的读者中提出疑问。您可以尝试通过文档解决此问题,但是可能有人会错过它并感到困惑。我建议使意图尽可能明确和可见,例如:

enum class ConstructFromBase { Tag };

struct Derived : Base
{
    Derived(Base&, ConstructFromBase);
    Derived(const Derived&) = delete;
};

Derived getDerived();

void test()
{
    Derived d1 = getDerived();
    Derived d2(d1, ConstructFromBase::Tag);
}
Run Code Online (Sandbox Code Playgroud)

https://godbolt.org/z/QfeuAM

这应该非常清楚地传达意图,并且几乎不花任何费用。(还有许多其他方式可以编写和命名此类标签,我的标签可能不是最规范的...)