如何在 C++ 中分配 const 成员变量之前验证它的初始化

How to validate the initialization of a const member variable before assigning it in C++

假设我有一个带有 const int 成员变量的简单 class:

class MyClass{
    public:
        Myclass(int x, int y);
    private:
        const int importantNumber;
        int anotherNumber;
};

MyClass::MyClass(int x, int y) :importantNumber{x}
{
    this->anotherNumber = y;
}

由于int importantNumber是const,我只能在构造函数创建对象时设置它(使用成员初始化列表,如上所示)。

现在,问题是:在实际创建具有该值的 importantNumber 之前,我怎么可能添加对给定构造函数的参数 x 的验证?是否可以创建一个 static int MyClass::validation(int a) 并在构造函数的成员初始化列表中使用它,如 importantNumber{validation(x)}?

即使可行,还有更好的方法吗?

你加就行了

MyClass::MyClass(int x, int y) : importantNumber{validate(x)}
{
    this->anotherNumber = y;
}

int validate(int original) 函数现在可以 return 除了 x 之外的其他东西,或者抛出异常或 assert 或者要求用户确认,无论你认为合适。 =16=]

如果这只是一个简单的检查并且您不想编写 validate 函数,您可以使用 lambda:

MyClass::MyClass(int x, int y) :importantNumber{
    [](int number){
        assert(number > 0);
        return number;
    }(x)}
{
    this->anotherNumber = y;
}

不过,如果你做得过头了,这可能会有点令人费解。

使用工厂函数创建 class 而不是构造函数。

class MyClass
{
public:
  static MyClass* create (int x, int y);

private:
  MyClass(int x, int y);

private:
  const int importantNumber;
  int anotherNumber;
};

MyClass* MyClass::create (int x, int y)
{
  return x > 0 ? new MyClass(x, y) : NULL;
}

当您需要对参数进行一些高级验证时,工厂具有以下优势:

  • 如果测试失败,他们会避免在内存中创建对象
  • 他们在检查初始化参数方面有更大的灵活性 名单
  • 如果您不需要异常也不希望为您的 [= 提供一些“.is_valid()”成员函数,您可以 return NULL 26=].

如果你想用一个简单的条件来验证,你可以在构造函数中使用三元运算符condition ? true : false

class MyClass{
    public:
        MyClass(int x, int y);
    private:
        const int importantNumber;
        int anotherNumber;
};

MyClass::MyClass(int x, int y) : importantNumber(x > 0 ? x : 0)
{
    this->anotherNumber = y;
}

但是,请注意,如果您过度使用此运算符,事情很快就会变得难以阅读。

对于更复杂的事情,你可以这样做:

int validateIntegral(int x) const
{
    // Do validation on 'x'...

    return x;
}

class MyClass{
    public:
        MyClass(int x, int y);
    private:
        const int importantNumber;
        int anotherNumber;
};

MyClass::MyClass(int x, int y) : importantNumber(validateIntegral(x))
{
    this->anotherNumber = y;
}