从未知指针转换为类;如何检查有效性?

时间:2011-07-03 22:08:13

标签: c++ windows casting

我正在使用LPARAM(基本上是long,除非我们在64位系统上,在这种情况下它是long long)成员{{1} }(称为LVITEM)存储指向与lParam中的条目重合的对象的指针。

当我想编辑该项目时,我想将ListView强制转换为LPARAM,只要MyClass*正确设置为等于{lParam,该工作正常首先是{1}},但我想做某种检查确保实际上是这个数字指向的MyClass*。< / p>

目前我有这个:

MyClass

现在,我并不完全清楚:如果参数不是有效指针,LVITEM lv; // lv is filled in by LVM_GETITEM classPtr = static_cast<MyClass*>((void*)lv.lParam); if ( !classPtr ) return false; 会返回static_cast吗?我假设没有,因为那是NULL的用途,但我并不完全确定。并且,如果我在这个假设中是正确的,那么在我尝试访问其成员并导致崩溃之前,有没有办法检查dynamic_cast是否有效......

6 个答案:

答案 0 :(得分:5)

static_cast<>不会对类型执行运行时检查,因此您所拥有的内容将无法工作,至少不会像您认为的那样。所有static_cast<>都是基于编译时已知的信息的指针算法。

dynamic_cast<> 可能工作,但它要求该类至少有一个虚拟函数(对于RTTI),如果LPARAM不是,它肯定会失败。甚至是指向类类型的指针。

在给定任意指针或整数值(如LPARAM)的情况下,没有一般方法可以确定它实际指向MyClass的实例。

在特定情况下我会做的是将列表视图包装在自己的类中,并公开仅适用于MyClass的方法。可能是这样的:

class MyListView
{
public:
    MyListView() { /* create the list view HWND */ }
    ~MyListView() { /* destroy the list view HWND */ }

    void Add(MyClass* listItem) // Only way to add items to list view
    {
        // Add to list view
    }

    MyClass* Get() const
    {
        LVITEM lv;
        // lv is filled in by LVM_GETITEM

        // Assume that this will work, since the only way to add
        // list view items is through Add(), and Add() only accepts
        // an instance of MyClass. Therefore the list view will only
        // have pointers to instances of MyClass.
        return static_cast<MyClass*>((void*)lv.lParam);
    }

    // ...

private:
    // Set to private so users can't modify
    // the list view without our consent.
    HWND listView;
};

这种方法的优点是,现在您可以完全控制列表视图控件及其界面,因此这将始终有效(尽管存在错误和恶意/无能的程序员)。您甚至可以将其设为模板,以便它适用于MyClass以外的类。

答案 1 :(得分:3)

您无法在纯标准C ++中查看它。您只能使用Windows API进行概率检查。因此,在实践中,您只能通过使代码正确来保证它。

如果你可以检查它,你仍然不知道它是 正确的MyClass实例。

因此,唯一的好方法是保证代码正确无误。当您限制对事物的访问时,这会更容易。 C ++有许多功能可以帮助您限制访问,例如const;使用它们。

干杯&amp;第h。,

答案 2 :(得分:2)

如果LPARAM不是MyClass类型的指针,而是任意位模式,则static_castdynamic_cast都将显示未定义的行为。如果指向有效对象的指针被强制转换为不相关的类,dynamic_cast将返回NULL,但它不支持检查特定内存中是否存在有效的多态对象位置。

除了维护MyClass*对象的有效指针的全局列表之外,没有智能的方法来检查这一点。

答案 3 :(得分:1)

几乎没有办法找出答案。你必须为所有对象创建一些父对象(让我们称之为grand_dad),然后从中继承所有对象。然后使用更改LPARAM到grand_dad*并使用dynamic_cast<MyClass*>(lv.lparam)

关于动态和静态演员的一点注意事项:

  • static_cast几乎总是做你要求的事情,根本没有检查!
  • 另一方面,
  • dynamic_cast检查对象是否可浇铸。如果不是它返回NULL指针。但它使用虚函数表来检查你的强制转换是否合法,所以如果编译器不知道要查找哪个函数表(例如,如果它是从void *转换),它总是返回NULL指针。如果您传递一个A的实例并调用dynamic_cast将其更改为B的isntance并且它们不是彼此的父级,那么您必须期待未经解释的行为。

答案 4 :(得分:0)

无需崩溃。在Windows中,使用structured exception handling

您还可以将LONG magic_number设为MyClass的第一个字段,并将其视为额外的保险,即它不是其他对象。

答案 5 :(得分:0)

到目前为止,最简单的解决方案是保留列表ov有效MyClass个对象。在每个ctor中,将this添加到列表中;在析构函数中,您将其从列表中删除。

这并不能保护您免受巧合,但即便如此,您也有一个有效的MyClass*。它甚至涵盖了派生类,因为它们确实调用了基础构造函数。