C++ 基础

2020-04-18  本文已影响0人  cb_guo

C 和 C++ 区别

cpp 分配内存的几种方式

cpp 内存
c/c++ 内存分配

cpp 类的大小

对象是类类型的一个变量,类则是对象的模板
类是抽象的,不占用存储空间;而对象是具体的,占用存储空间

c++ 对象内存分布

最权威结论是:非静态成员变量总和加上编译器为了CPU计算做出的数据对齐处理和支持虚函数所产生的负担的总和
C++ 中每个空类型的实例(类为空的对象)占1Byte空间
静态数据成员是不占对象的内存空间的
成员函数不占空间
构造函数和析构函数不占空间
编译器为了支持虚函数,会产生额外的负担,这正是指向虚函数表的指针的大小
函数代码段是公用的,即如果一个类定义了10个对象,这些对象的成员函数所对应的是同一个函数代码段,而不是10个不同的函数代码段

引用和指针区别

本质上的区别是,指针是一个新的变量,只是这个变量存储的是另一个变量的地址,我们通过访问这个地址来修改变量。
引用只是一个别名,还是变量本身。对引用进行的任何操作就是对变量本身进行操作,因此以达到修改变量的目的

(1)指针:指针是一个变量,只不过这个变量存储的是一个地址,指向内存的一个存储单元;
而引用跟原来的变量实质上是同一个东西,只不过是原变量的一个别名而已。如:
int a=1;int *p=&a;
int a=1;int &b=a;
上面定义了一个整形变量和一个指针变量p,该指针变量指向a的存储单元,即p的值是a存储单元的地址。
而下面2句定义了一个整形变量a和这个整形a的引用b,事实上a和b是同一个东西,在内存占有同一个存储单元。
(2)可以有const指针,但是没有const引用(const引用可读不可改,与绑定对象是否为const无关)
(3)指针可以有多级,但是引用只能是一级(int **p;合法 而 int &&a是不合法的)
(4)指针的值可以为空,但是引用的值不能为NULL,并且引用在定义的时候必须初始化;
(5)指针的值在初始化后可以改变,即指向其它的存储单元,而引用在进行初始化后就不会再改变了。
(6)"sizeof引用"得到的是所指向的变量(对象)的大小,而"sizeof指针"得到的是指针本身的大小;
(7)指针和引用的自增(++)运算意义不一样;
#include<iostream>
#include<vector>
using namespace std;
int main(){
    vector<int> aa;
    aa.push_back(1);
    aa.push_back(2);
    aa.push_back(3);
    aa.push_back(4);
    aa.push_back(5);
    vector<int>::iterator it = aa.end()-1;
    cout<<*it<<endl;        // 5
    aa.insert(aa.begin(), 1, 0);  // 在最前面插入一个0
    
    vector<int>::iterator tt;
    for(tt = aa.begin(); tt != aa.end(); tt++){
        cout<<*tt<<" ";    //  0 1 2 3 4 5
    }
    cout<<*it<<endl;       // 4
}
#include<iostream>
#include<vector>
using namespace std;
int main(){
    vector<int> aa;
    aa.push_back(1);
    aa.push_back(2);
    aa.push_back(3);
    aa.push_back(4);
    aa.push_back(5);
    vector<int>::iterator it = aa.end()-3;
    cout<<*it<<endl;  // 3       
    
    aa.erase(it);
    cout<<*it<<endl;  // 4  
    vector<int>::iterator tt;
    for(tt = aa.begin(); tt != aa.end(); tt++){
        cout<<*tt<<" ";   // 1 2 4 5 
    }
    cout<<endl;
}
比如数字 0x12345678 在两种不同字节序 CPU 中的存储顺序如下所示
1)大端模式:
    低地址 -----------------> 高地址
    0x12  |  0x34  |  0x56  |  0x78
2)小端模式:
    低地址 ------------------> 高地址
    0x78  |  0x56  |  0x34  |  0x12

为什么要注意字节序的问题呢?
如果程序只在单机环境下运行,并且不和其他程序打交道,那么完全可以忽略字节序的存在;
但是,如果程序要跟其他程序产生交互呢,此时就一定需要注意写字节序的问题。C/C++ 语言编写的程序里数据存储顺序是跟编译平台所在 CPU 相关的,而 JAVA 编写的程序则唯一采用 大端模式 来存储数据
试想,如果你用 C/C++ 语言在 x86 平台下编写的程序跟别人的 JAVA 程序互通时会产生什么结果? 就拿上面的 0x12345678 来说,将指向 0x12345678 的指针指向 JAVA 程序,由于 JAVA 采用大端方式存储数据,很自然会将你的数据翻译成 0x78563412 。因此,在你的 C 程序传给 JAVA 程序之前有必要进行字节序的转换工作
无独有偶,所有网络协议也都是采用大端模式来传输数据。所以有时也会把大端方式称之为网络字节序当两台采用不同字节序的主机通信时,在发送数据之前都必须经过字节序的转换成为网络字节序后再进行传输

预处理器的主要作用就是把通过预处理的内建功能对一个资源进行等价替换,
最常见的预处理有:文件包含,条件编译、布局控制和宏替换4种。

文件包含:
#include 是一种最为常见的预处理,主要是做为文件的引用组合源程序正文。

条件编译:
#if,#ifndef,#ifdef,#endif,#undef等也是比较常见的预处理,主要是进行编译时进行有选择的挑选,
注释掉一些指定的代码,以达到版本控制、防止对文件重复包含的功能。

布局控制:
#progma,这也是我们应用预处理的一个重要方面,主要功能是为编译程序提供非常规的控制流信息。

宏替换:
#define,这是最常见的用法,它可以定义符号常量、函数功能、重新命名、字符串的拼接等各种功能。
上一篇 下一篇

猜你喜欢

热点阅读