编译时进行C ++类型检查

时间:2010-04-12 06:47:46

标签: c++ boost polymorphism assignment-operator typechecking

所有。我是C ++的新手,我正在用C ++编写一个小型库(主要用于我自己的项目)。在设计类型层次结构的过程中,我遇到了定义赋值运算符的问题。

我采用了最终在this article中达到的基本方法,即对于从类MyClass派生的层次结构中的每个类Base,您定义了两个赋值运算符,如这样:

class MyClass: public Base {
public:
    MyClass& operator =(MyClass const& rhs);
    virtual MyClass& operator =(Base const& rhs);
};

// automatically gets defined, so we make it call the virtual function below
MyClass& MyClass::operator =(MyClass const& rhs);
{
    return (*this = static_cast<Base const&>(rhs));
}

MyClass& MyClass::operator =(Base const& rhs);
{
    assert(typeid(rhs) == typeid(*this)); // assigning to different types is a logical error
    MyClass const& casted_rhs = dynamic_cast<MyClass const&>(rhs);
    try {
        // allocate new variables
        Base::operator =(rhs);
    } catch(...) {
        // delete the allocated variables
        throw;
    }
    // assign to member variables
}

我关注的部分是类型相等的断言。由于我正在编写一个库,其中断言可能是从最终结果中编译出来的,这使我开始采用看起来更像这样的方案:

class MyClass: public Base {
public:
    operator =(MyClass const& rhs); // etc
    virtual inline MyClass& operator =(Base const& rhs)
    {
        assert(typeid(rhs) == typeid(*this));
        return this->set(static_cast<Base const&>(rhs));
    }
private:
    MyClass& set(Base const& rhs); // same basic thing
};

但我一直想知道是否可以在编译时检查类型。我查看了Boost.TypeTraits,接近我做了BOOST_MPL_ASSERT((boost::is_same<BOOST_TYPEOF(*this), BOOST_TYPEOF(rhs)>));,但由于rhs被声明为对父类的引用而不是派生类,因此它会被阻塞。

现在我考虑一下,我的推理似乎很愚蠢 - 我希望由于函数是内联的,它可以自己检查实际参数,但当然预处理器总是在编译器之前运行。但是我想知道是否有人知道我可以在编译时强制执行这种检查。

2 个答案:

答案 0 :(得分:7)

您无法在编译时执行此断言,原因很简单,直到运行时才会知道运行时类型。

assert(typeid(rhs) == typeid(*this));
return this->set(static_cast<Base const&>(rhs));

在非内联版本中,您有dynamic_cast。如果你的断言被违反,我会保留这个以便你得到一个明确定义的错误而不是未定义的行为。

如果你这样做,断言要么过于严格,要么毫无意义。 dynamic_cast将在调试和发布版本中抛出bad_cast异常。这就是你想要的。

就个人而言,我会质疑整个多态分配问题。我会遵循Scott Meyers的Effective C ++建议,并在继承层次结构中抽象所有非叶子节点。然后,您可以使基类赋值运算符受保护且非虚拟。

这使您可以在派生类赋值运算符中使用它们的实现,但可以防止客户端对对象进行切片。如果客户端类只有一个基类引用或指针,那么无论如何都应该尝试分配给该类是有疑问的。如果这样做,他们应该负责铸造和类型安全保障。

答案 1 :(得分:0)

如果您希望在编译时确定事物,那么动态多态(虚函数等)不适合您。我通常不认为需要将动态多态性与“正常值类型”之类的东西混合 - 就像赋值运算符一样。也许具体和非多态类是最适合您的情况。但是很难说,因为你没有说过你要对这些课程做些什么。