初始化派生类中基于 C 的 API 提供的基于 C 的类型定义结构?

Initialize C-based typedef'd structure provided by C-Based API in derived class?

本文关键字:类型 定义 结构 初始化 派生 API      更新时间:2023-10-16

我有一个OVERLAPPED,我试图把在一个已知的良好状态。OVERLAPPED是一个由Win32 API提供的Windows类型定义的结构。我不能改变它。

#pragma push_macro ("WIN32_LEAN_AND MEAN")
#pragma push_macro ("NOMINMAX")
#define WIN32_LEAN_AND MEAN
#define NOMINMAX
#include <windows.h>
struct OverlappedIo : public OVERLAPPED
{
    explicit OverlappedIo()
        : Internal(0), InternalHigh(0), Offset(0), OffsetHigh(0)
        , Pointer(NULL), hEvent(hEvent) { }
    ...
};
#pragma pop_macro ("NOMINMAX")
#pragma pop_macro ("WIN32_LEAN_AND MEAN")

在MinGW下,它会导致(它可能在本地Win32下有问题;我还没有开始测试平台):

g++ -DNDEBUG -g -O2 -march=native -pipe -c network.cpp
In file included from network.cpp:4:0:
network.h: In constructor 'OverlappedIo::OverlappedIo()':
network.h:244:5: error: class 'OverlappedIo' does not have any field n
amed 'Internal'
   : Internal(0), InternalHigh(0), Offset(0), OffsetHigh(0)
     ^
...

我也尝试了_OVERLAPPED与相同的结果。当我试图提供缺失的构造函数来执行c++初始化时(我没有期望这能工作,但值得一试):

//! OVERLAPPED I/O
OVERLAPPED::OVERLAPPED()
    : Internal(0), InternalHigh(0), Offset(0), OffsetHigh(0), hEvent(NULL) { }

结果是:

In file included from network.cpp:4:0:
network.h:24:24: error: ISO C++ forbids declaration of 'OVERLAPPED' with no type
 [-fpermissive]
 OVERLAPPED::OVERLAPPED()
                        ^

在c++ 11中,我相信我可以用大括号初始化。但是我不清楚如何在c++ 03中实现它。还要注意,这是一个简化的例子,真正的类要复杂得多,它试图提供更强的异常安全性。由于更强的异常安全性,我想初始化字段,而不是对它们进行memset或赋值。(对于"initialize"answers"assign"这两个词,我很抱歉)。

是否可以从C中初始化类型定义的结构?

如果是,如何在c++ 03中初始化结构体的字段?


相关的,这是<windows.h>的结构体:

typedef struct _OVERLAPPED {
    ULONG_PTR Internal;
    ULONG_PTR InternalHigh;
    union {
        struct {
            DWORD Offset;
            DWORD OffsetHigh;
        } DUMMYSTRUCTNAME;
        PVOID Pointer;
    } DUMMYUNIONNAME;
    HANDLE  hEvent;
} OVERLAPPED, *LPOVERLAPPED;

c++结构体的成员是否默认初始化为0 ?以及在类构造函数中初始化结构的正确方法。它也与类型名后面的括号与new有区别吗?(我试图避免愚蠢的规则,只是把一个对象放在一个已知的良好状态)。

我不愿意以这种方式处理问题:如果OVERLAPPED以任何方式更改,您的代码都可能无效。如果您希望所有成员都被初始化,那么将来向OVERLAPPED添加的任何成员都可能给程序引入未定义行为。

另外,请注意OVERLAPPED可能不是多态类型,因此在程序开发时可能容易出现内存泄漏。

考虑使用类的OVERLAPPED成员变量,并在构造函数中通过调用memset将结构初始化为0。

OVERLAPPED是由pod组成的结构,试图假装它不是毫无意义的。在我看来,使用memset:

初始化并没有错。
struct OverlappedIo : public OVERLAPPED
{
    OverlappedIo(HANDLE e = 0)
    {
        memset(this, 0, sizeof(OVERLAPPED));
        hEvent = e;
    }
};

成员Internal和其他成员是从基类继承的,继承的成员不能在派生类的初始化列表中初始化。

从逻辑上讲,基类的成员在派生类的成员开始初始化时就已经构造好了(并初始化了1)。

<一口> 1。虽然在这种情况下,类型是内置类型,不会初始化为任何合理的值,除非您显式地将它们初始化为。所谓的内置类型的默认初始化意味着未初始化的。因此,在派生类构造函数体中,您可以赋予合理的值。

这将在c++ 03中对所有内容进行零初始化(但不包括c++ 98):

OVERLAPPED x = OVERLAPPED();

我不确定你是否真的有一个很好的理由想要派生,或者如果这只是为了初始化,但是如果你这样做了:

struct OverlappedIo: OVERLAPPED
{
    OverlappedIo(): OVERLAPPED() {}
    OverlappedIo(HANDLE h): OVERLAPPED() { hEvent = h; }
};

当然,添加构造函数意味着不能再使用聚合初始化。

在c++ 11中,当然你可以直接写OVERLAPPED x{};