必须设置变量的纯虚函数

Pure virtual function which must set variable

本文关键字:函数 变量 设置      更新时间:2023-10-16

最近我读了一些关于 C++ 中纯虚函数概念的文章,我想知道,给定以下代码:

class First
{
public: 
    virtual void init() = 0;
protected: 
    bool initialized;
};
class Second : public First
{
public:
    void init() { ((*someting*) ? (initialized=true) : (initialized=false)); 
};

如果类First创建者想要确保实现init()必须设置变量initialized真或假,他们怎么能做到这一点?是否有一个选项来强制实现纯虚函数来设置从基类继承的任何变量?

您可以保护init并使其返回bool 。然后有一个新的initialize方法,该方法是公共的,并且还设置initialized成员。

由于init现在有一个返回值,因此它必须由实现派生类的任何人设置。

class First
{
public: 
    void initialize() { initialized = init(); }
protected: 
    virtual bool init() = 0;
    bool initialized;
};
class Second : public First
{
public:
    bool init() { return (*something*); }
};

您无法检查是否已设置initialized,因为它不能表示第三个状态"未定义"。

解决方案 1

保护纯虚函数,使其返回初始化值并通过非虚拟包装器调用它

class First
{
public: 
    void init()
    {
        initialized = initImplementation();
        // check initialized here
    }
protected: 
    virtual bool initImplementation() = 0;
    bool initialized;
};

解决方案 2

将初始化更改为状态未定义、未初始化、已初始化的枚举,保护纯虚函数并通过非虚拟包装器调用它,然后检查变量是否已设置:

class First
{
public: 
    void init()
    {
        initImplementation();
        // check initialized here
    }
protected: 
    virtual void initImplementation() = 0;
    enum
    {
        undefined,
        initialized,
        uninitialized
    } initialized;
};

解决方案 3

摆脱初始化,如果出现问题,只需在init()抛出异常即可。然后,呼叫者将知道出了点问题。作为旁注,您也可以从构造函数中抛出。

好吧,虽然你的问题的直接答案是否定的。您可以使用一些技术来保证调用init函数。假设您有以下基类:

class Base
{
public:
    virtual void init() = 0;
private:
    bool initialized = false;
};
void Base::init() 
{
    std::cout << "Called from base!n";
    initialized = true;
}

并得出以下内容:

class Derived: public Base
{
    friend class Enforcer<Derived>;
public:
    void init() override
    {
        std::cout << "Called from derived!n";
    }
private:
    Derived()
    {
    }
private:
    using BaseClass = Base;
};

看看私有构造函数和 friend 声明:如果没有 Enforcer 类的帮助,你就不能再创建这个类了(这一步并不是真正必需的,但它确实会强制 Derived 类的任何用户使用 Enforcer )。现在我们需要编写Enforcer类,这里是:

template<typename T>
class Enforcer: public T
{
public:
    template<typename... Args>
    Enforcer(Args&&... arg): T(std::forward<Args>(arg)...)
    {
    }
    void init() override
    {
        T::init();
        T::BaseClass::init();
    }
};

关于 ideone 的整个示例。

是的,它有其缺点(您需要向Derived类添加一些额外的东西),但在我看来,它非常巧妙地解决了这一要求。