相关疑难解决方法(0)

什么是聚合和POD以及它们如何/为何特殊?

常见问题解答涉及聚合和POD,并涵盖以下材料:

  • 什么是聚合
  • 什么是POD(普通旧数据)?
  • 它们有什么关系?
  • 它们如何以及为何特别?
  • C++ 11有什么变化?

c++ aggregate standard-layout c++11 c++17

525
推荐指数
6
解决办法
13万
查看次数

这种向下倾斜是不确定的?

考虑这个例子,其中基类有一些数据成员,而派生类只提供了一个额外的方法:

struct TestBase
{
    int x;
    TestBase() : x(5) {}
};

struct TestDerived : public TestBase
{
    void myMethod()
    {
        x=8;
    }
};

int main()
{
    TestBase b;
    TestDerived& d=static_cast<TestDerived&>(b);
    d.myMethod();
}
Run Code Online (Sandbox Code Playgroud)

这是向下错误的类型,所以AFAIU它有未定义的行为.但是这样的情况可能会有一些例外吗,派生类的布局与基类的布局相同?

c++ downcast undefined-behavior

11
推荐指数
1
解决办法
372
查看次数

P ++中的POD和继承11.结构的地址=第一个成员的地址吗?

(我编辑了这个问题是为了避免干扰.在任何其他问题有意义之前,有一个核心问题需要澄清.对现在的答案似乎不太重要的任何人道歉.)

让我们建立一个具体的例子:

struct Base {
    int i;
};
Run Code Online (Sandbox Code Playgroud)

没有虚方法,也没有继承,通常是一个非常愚蠢和简单的对象.因此,它是普通旧数据(POD),它可以回溯到可预测的布局.特别是:

Base b;
&b == reinterpret_cast<B*>&(b.i);
Run Code Online (Sandbox Code Playgroud)

这是根据维基百科(它本身声称参考C++ 03标准):

指向一个POD结构对象,适宜地转换使用重新解释铸造,点到它的初始构件,反之亦然,这意味着有在POD结构的开头没有填充.[8]

现在让我们考虑继承:

struct Derived : public Base {
};
Run Code Online (Sandbox Code Playgroud)

同样,没有虚方法,没有虚继承,也没有多重继承.因此这也是POD.

问题:这个事实(Derived是C++ 11中的POD)是否允许我们这样说:

Derived d;
&d == reinterpret_cast<D*>&(d.i); // true on g++-4.6
Run Code Online (Sandbox Code Playgroud)

如果这是真的,那么以下将是明确定义的:

Base *b = reinterpret_cast<Base*>(malloc(sizeof(Derived)));
free(b); // It will be freeing the same address, so this is OK
Run Code Online (Sandbox Code Playgroud)

我不会在这里问newdelete- 这更容易考虑mallocfree.在这种简单的情况下,我只是对有关派生对象布局的规定感到好奇,并且基类的初始非静态成员位于可预测的位置.

Derived对象应该等效于:

struct Derived { // no inheritance
    Base b; // …
Run Code Online (Sandbox Code Playgroud)

c++ language-lawyer c++11

7
推荐指数
1
解决办法
3074
查看次数

C ++设计:从基类转换为派生类,没有额外的数据成员

我写了很多处理消息协议的代码。消息协议通常会具有通用的消息帧,可以从串行端口或套接字反序列化。该帧包含消息类型,并且必须根据消息类型来处理消息有效负载。

通常,我用访问器方法和构造函数编写一个多态类集,该构造函数引用消息框。

我想到的是,我可以直接从消息框架派生访问器类,然后从消息框架重新解释_cast到适当的访问器类,而不是基于对消息框架的引用来构造访问器类。这使代码更加简洁,并节省了一些字节和处理器周期。

请参见下面的示例(极度虚构和压缩)。显然,对于生产代码,所有这些都需要适当地封装,强制转换成为派生类的成员,更好地分离了所关注的问题,并添加了一些验证。为了简洁起见,已全部删除。

#include <iostream>
#include <cstring>
#include <vector>

struct GenericMessage
{
  GenericMessage(const char* body):body_(body, body+strlen(body)){}
  std::vector<char> body_;  
};

struct MessageType1:public GenericMessage
{
    int GetFoo()const
    {
        return body_[2];
    }
    int GetBar()const
    {
        return body_[3];
    }    
};

int main() 
{
    GenericMessage myGenericMessage("1234");
    MessageType1* myMgessageType1 = reinterpret_cast<MessageType1*>(&myGenericMessage);
    std::cout << "Foo:" << myMgessageType1->GetFoo() << std::endl;
    std::cout << "Bar:" << myMgessageType1->GetBar() << std::endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我从来没有见过任何地方这样做。考虑到派生没有其他数据成员,以这种方式从基础到派生有任何不利之处吗?

c++ inheritance

6
推荐指数
1
解决办法
1376
查看次数