POD,全称plain old data,plain代表它是一个普通类型,old代表它可以与c兼容,可以使用比如memcpy()这类c中最原始函数进行操作。C++11中把POD分为了两个基本概念的集合,即:平凡的(trival)和标准布局的(standard layout)。

1、首先是平凡的(trival)定义,通常一个平凡的类或者结构体需要满足以下定义

  (1).拥有平凡的默认构造函数和析构函数。默认的意思就是由编译器为我们自动生成的,不许是我们自己定义的,而一旦定义了构造函数,即使函数体里没有任何代码,那么该构造函数也不在是平凡的,但是由于c++11提供了default,也可以是自己定义的加=default。

  (2).拥有平凡的拷贝构造函数和移动构造函数。默认的意思同上,也可以使用=default。

  (3).拥有平凡的拷贝赋值运算符和移动赋值运算符。

  (4).不能包含虚函数和虚基类。

C++11中,我们使用模版类std::is_trivial<T>::value来判断数据类型是否为平凡类型。

#include "stdafx.h"
#include <iostream> using namespace std; class A { A(){} };
class B { B(B&){} };
class C { C(C&&){} };
class D { D operator=(D&){} };
class E { E operator=(E&&){} };
class F { ~F(){} };
class G { virtual void foo() = ; };
class H : G {};
class I {}; int _tmain(int argc, _TCHAR* argv[])
{
std::cout << std::is_trivial<A>::value << std::endl; //有不平凡的构造函数
std::cout << std::is_trivial<B>::value << std::endl; //有不平凡的拷贝构造函数
std::cout << std::is_trivial<C>::value << std::endl; //有不平凡的拷贝赋值运算符
std::cout << std::is_trivial<D>::value << std::endl; //有不平凡的拷贝赋值运算符
std::cout << std::is_trivial<E>::value << std::endl; //有不平凡的移动赋值运算符
std::cout << std::is_trivial<F>::value << std::endl; //有不平凡的析构函数
std::cout << std::is_trivial<G>::value << std::endl; //有虚函数
std::cout << std::is_trivial<H>::value << std::endl; //有虚基类
std::cout << std::is_trivial<I>::value << std::endl; //平凡的类return ;
}

2.接下来是标准布局的定义

(1).所有非静态成员拥有相同的访问级别,(访问级别就是public,private,protected)

struct t1{
private :
  int a;
public:
  int b;
}; //不满足标准布局,因为a,b访问级别不同。

(2).在类和结构体继承时需要满足以下两个情况之一:

  派生类中有非静态类,那么这个派生类只能有且只有一个仅包含了静态成员的基类。

  基类有非静态成员,那么派生类中不允许有非静态成员。

(这两句话看着挺绕口,其实就是在说明一个事实,关于非静态数据的事实,派生类中有非静态的数据那么它的基类只能是只有静态的,而且基类只能有一个。如果基类有非静态的, 那么派生类就不能有非静态的。有种跷跷板的感觉,非静态的对面坐着的是静态,父子类就 是坐在跷跷板的两端这种对应关系。)

(3).类中第一个非静态类型与基类不是同一个类型。比如

struct A:B{
B b;
int c;
} //不符合这个条件。因为A中第一个成员是基类B类型的

(4).没有虚类和虚基类(与trival中重复)

(5).所有非静态数据成员都符合标准布局的要求,这其实就是一个递归的定义。

C++11中,我们使用模版类std::is_standard_layout<A>::value来判断类型是否是一个标准布局类型。

所以在C++11中,POD就是满足平凡的(trival)和标准布局(standard layout)这两个方面。

可以使用<type_traits>中的is_pod<T>::value判断T是不是POD类型的。
#include <iostream>

using namespace std;

class A {
private:
int a;
public:
int b;
}; class B1 {
static int x1;
}; class B2 {
int x2;
}; class B : B1, B2 {
int x;
}; class C1 {};
class C : C1 {
C1 c;
}; class D { virtual void foo() = ; };
class E : D {};
class F { A x; }; int main()
{
std::cout << std::is_standard_layout<A>::value << std::endl; //违反定义1,成员a和b具有不同的访问权限
std::cout << std::is_standard_layout<B>::value << std::endl; //违反定义2,继承树有两个(含)以上的类有非静态成员
std::cout << std::is_standard_layout<C>::value << std::endl; //违反定义3,第一个非静态成员是基类类型
std::cout << std::is_standard_layout<D>::value << std::endl; //违反定义4,有虚函数
std::cout << std::is_standard_layout<E>::value << std::endl; //违反定义5,有虚基类
std::cout << std::is_standard_layout<F>::value << std::endl; //违反定义6,非静态成员x不符合标准布局类型
return ;
}
#include <iostream>
#include <cstring> using namespace std; class AA
{
public:
int x;
double y;
}; int main()
{
if (std::is_pod<AA>::value) {
cout << "before" << endl;
AA aa;
aa.x = ;
aa.y = 20.0f;
cout << aa.x << " " << aa.y << endl; size_t size = sizeof(aa);
char *p = new char[size];
memcpy(p, &aa, size); AA *pA = (AA*)p;
cout << "after" << endl;
cout << pA->x << " " << pA->y << endl;
delete p;
}
return ;
}

说了这么多,那么为什么我们需要POD这种条件满足的数据呢?

  (1).可以使用字节赋值,比如memset,memcpy操作

  (2).对C内存布局兼容。

  (3).保证了静态初始化的安全有效。

C++11 POD类型的更多相关文章

  1. c++11 pod类型(了解)

    啥是POD类型? POD全称Plain Old Data.通俗的讲,一个类或结构体通过二进制拷贝后还能保持其数据不变,那么它就是一个POD类型. 平凡的定义 .有平凡的构造函数 .有平凡的拷贝构造函数 ...

  2. POD类型

    POD类型 POD全称Plain Old Data.通俗的讲,一个类或结构体通过二进制拷贝后还能保持其数据不变,那么它就是一个POD类型. C++11将POD划分为两个基本概念的合集,即:平凡的和标准 ...

  3. 3. C++ POD类型

    POD全称Plain Old Data,通常用于说明1个类型的属性.通俗的讲,一个类或结构体通过二进制拷贝后还能保持其数据不变,那么它就是一个POD类型. C++11将POD划分为2个基本概念的合集, ...

  4. 聚合类型与POD类型

    Lippman在<深度探索C++对象模型>的前言中写道: I have heard a number of people over the years voice opinions sim ...

  5. C++ POD 类型

    POD 是 C++ 中一个比较重要的概念,POD 是英文 Plain Old Data 的缩写(通俗讲就是类或结构体通过二进制拷贝后还能保持其数据不变),用来描述一个类型(包括 class.union ...

  6. C++ trivial和non-trivial构造函数及POD类型(转)

    原博客地址http://blog.csdn.net/a627088424/article/details/48595525 最近正纠结这个问题就转过来了,做了点补充(参考<深度探索C++对象模型 ...

  7. 关于POD和非POD类型中,list initialization和constructor initialization(未解决)

    如果你的成员是POD类型的,那么list initialization和constructor initialization没有任何区别 #include<iostream> using ...

  8. 关于C++ 中POD类型的解析

    转自: http://liuqifly.spaces.live.com/blog/cns!216ae3a149106df9!221.entry (C++-98:1.8;5)给出的定义:将对象的各字节拷 ...

  9. C++ POD类型

    POD( Plain Old Data)概念: Arithmetic types (3.9.1), enumeration types, pointer types, and pointer to m ...

随机推荐

  1. java动态代理技术

    主要用来做方法的增强.让你能够在不改动源代码的情况下,增强一些方法,在方法运行前后做不论什么你想做的事情(甚至根本不去运行这种方法).由于在InvocationHandler的invoke方法中,你能 ...

  2. OSS设置CORS规则以后还是报No 'Access-Control-Allow-Origin'解决方法

    OSS设置CORS规则以后还是报No 'Access-Control-Allow-Origin'解决方法 在OSS控制台设置了CORS规则以后,通过JS程序去调用的时候报No 'Access-Cont ...

  3. 设置mysql group_concat长度

    #在MySQL配置文件(my.ini)中默认无该配置项,使用默认值时,值为1024,可在客户端执行下列语句修改: #SET GLOBAL group_concat_max_len = 1024; #该 ...

  4. 【TP3.2】详解_initialize() 和 __construct() 的区别和联系

    1.假设 一个AdminController.class.php 集成至 \Think\Controller 类, 我们来看看Controller.class.php的构造方法源码: /** * 架构 ...

  5. iPhone开发之在UINavigationBar上使用UISegmentedControl制作

    UISegmentedControl *segmentedControl=[[UISegmentedControl alloc] initWithFrame:CGRectMake(80.0f, 7.0 ...

  6. iOS Main Thread Checker: UI API called on a background thread的解释

    Xcode打印栏出现如下警告: Main Thread Checker: UI API called on a background thread 这个是什么错误呢? 其实这并不一定是错误,也可以理解 ...

  7. 给我一对公钥和私钥,我就能破解此RSA

    RSA密码系统如果暴露了一套公钥和私钥,那么这套密码系统就全部失效了.因为根据公钥和私钥可以完成大整数的分解.暴露了两个质数. 记公钥为e,私钥为d,因为ed%phi=1,所以就得到了一个k=ed-1 ...

  8. 虚拟机virtualbox中挂载新硬盘

    在virtualbox中装好Ubuntu后,发现硬盘空间太小,怎样才能增加硬盘容量?那就是再建一个硬盘: 1. 添加新硬盘 设置 -> Storage -> SATA控制器->右击, ...

  9. MFC的DLL中实现定时器功能

    方法一:创建一个线程, 反复读系统时间不就可以了? 如果定时要求不严,用Sleep就可以了.DWORD WINAPI TimerThread(LPVOID pamaram) { UINT oldTic ...

  10. 创建在“system.net/defaultProxy”配置节中指定的Web代理时出错解决办法。

    出现这种问题会有很多原因,大致解决方法 方法1:在CMD下输入netsh winsock reset命令 简单来说netsh winsock reset命令含义是重置 Winsock 目录.如果一台机 ...