C++编译时类型检查

发布于 2024-08-28 07:52:10 字数 1876 浏览 11 评论 0原文

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

我采用了本文中最终达到的基本方法,也就是说,对于从类 Base 派生的层次结构中的每个类 MyClass,您定义两个赋值运算符,如下所示:

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)); 接近了,但由于 rhs 被声明为对父类而不是派生类的引用,就窒息了。

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

all. I'm pretty new to C++, and I'm writing a small library (mostly for my own projects) in C++. In the process of designing a type hierarchy, I've run into the problem of defining the assignment operator.

I've taken the basic approach that was eventually reached in this article, which is that for every class MyClass in a hierarchy derived from a class Base you define two assignment operators like so:

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
}

The part I'm concerned with is the assertion for type equality. Since I'm writing a library, where assertions will presumably be compiled out of the final result, this has led me to go with a scheme that looks more like this:

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
};

But I've been wondering if I could check the types at compile-time. I looked into Boost.TypeTraits, and I came close by doing BOOST_MPL_ASSERT((boost::is_same<BOOST_TYPEOF(*this), BOOST_TYPEOF(rhs)>));, but since rhs is declared as a reference to the parent class and not the derived class, it choked.

Now that I think about it, my reasoning seems silly -- I was hoping that since the function was inline, it would be able to check the actual parameters themselves, but of course the preprocessor always gets run before the compiler. But I was wondering if anyone knew of any other way I could enforce this kind of check at compile-time.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

千と千尋 2024-09-04 07:52:10

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

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

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

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

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

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

You can't perform this assert at compile time for the simple reason that the run-time types won't be known until, well, run time.

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

In the non-inline version you had dynamic_cast. I would retain this so that you get a well-defined error and not undefined behaviour if your assertion is violated.

If you do this the assertion is either overly restrictive or pointless. The dynamic_cast will throw a bad_cast exception in both debug and release builds. This is what you want.

Personally, I would question the whole polymorphic assignment issue. I would follow Scott Meyers' Effective C++ advise and make all your non-leaf nodes in the inheritance hierarchy abstract. You can then make the base class assignment operators protected and non-virtual.

This enables you to use their implementation in derived classes assignment operator but prevents clients from slicing objects. If a client class has only a base class reference or pointer it is questionable whether the should be attempting to assign to the class anyway. If the do, they should be responsible for the casting and type safety guarantees.

旧伤慢歌 2024-09-04 07:52:10

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

If you want things to be determined at compile-time, then dynamic polymorphism (virtual functions, etc) is not the right tool for you. I generally don't see the need to mix dynamic polymorphism with things "normal value types" have -- like assignment operators. Maybe concrete and non-polymorphic classes is what works best in your case. But it's hard to tell because you havn't said anything about what you're trying to do with the classes.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文