1

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

我采用了本文最终达到的基本方法,即对于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 被声明为对父类而不是派生类的引用,所以它窒息了。

现在我想起来了,我的推理似乎很愚蠢——我希望由于函数是内联的,它能够自己检查实际参数,但当然预处理器总是在编译器之前运行。但我想知道是否有人知道我可以在编译时强制执行这种检查的任何其他方式。

4

2 回答 2

7

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

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

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

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

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

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

于 2010-04-12T07:02:26.613 回答
0

如果您希望在编译时确定事情,那么动态多态性(虚拟函数等)不是适合您的工具。我通常不认为需要将动态多态性与“正常值类型”所具有的东西混合在一起——比如赋值运算符。也许具体和非多态类最适合您的情况。但这很难说,因为你没有说任何关于你试图用这些课程做什么。

于 2010-04-12T06:53:11.473 回答