c++最难的就是内存和指针
1、学习内容
数据类型,数组,内存布局,物理内存,虚拟内存。
内存的概念:app内存。两个角度
(1、硬件角度:内存是计算机必不可少的一个组成部分,是与CPU沟通的桥梁,计算机中所有的程序都是运行在内存中,例如内存条)
(2、逻辑角度:内存是一块具备随机访问能力,支持读、写操作,用来存放程序及程序运行中产生数据的区域)
内存的单位:
位(bit)是电子计算机中最小的数据单位,每一位的状态只能是0或1。字节(Byte):1Byte = 8bit,是内存基本的计量单位。
内存的编址:
计算机中的内存按字节编址,每个地址的储存单位可以存放一个字节(8个bit)的数据,CPU通过内存地址获取指令和数据,并不关心这个地址所代表的空间具体在什么位置,怎么分布,因为硬件的设计保证一个地址对应着一个固定的空间,所以说:内存地址和地址指向的空间共同构成一个内存单元。
内存的地址:在java中指的是对象的引用,内存地址通常用十六进制的数据表示,指向内存中的某一块区域。
内存地址的分配规则,是连续的,一个挨着一个,当对象需要申请内存时,先给这个对象分配一个编码,这个编码就是内存地址。
内存对象和内存地址的区别
基本数据类型,c和java的long类型。c4个,java8个
内存的组成
基础函数
Android内存组成
C语言内存组成
BSS段-存放全局变量
数组和指针,数组指针,指针数组
指针数组,每一个数组都是一个指针地址
指针的优先级
定义: () > [] > *
数组指针(也称为行指针)
定义:int (*p)[n]
优先级高,首先说明p是一个指针,指向一个整形的一维数组,这个一维数组的长度是n,也可以说是p的步长,也就是说执行p+1时,p要跨过n个整形数组的长度。
结构体共同体
使用struct关键字来定义
结构体大小:当结构体需要内存过大,使用动态内存申请。结构体占用字节数和结构体内字段有关,指针占用内存就是4/8字节,因此传指针比传值效率更高。
内存对齐:对齐跟数据在内存中的位置有关。如果一个变量的内存地址正好位于它长度的整数倍,他就被称作自然对齐,比如在32位cpu下,假设一个整形变量的地址为0x00000004那它就是自然对齐。
结构体储存原则:(1)、结构体变量中成员的偏移量必须是成员大小的整数倍(0是任意数的整数倍)
(2)、结构体大小必须是所有成员大小的整数倍,也即所有成员大小的公倍数。
共用体:共用体是一种特殊的数据类型,允许您在相同的内存位置储存不同的数据类型。你可以定义一个带有多成员的共用体,但是任何时候只能由一个成员带有值。共用体提供了一种使用相同的内存位置有效方式。
共用体的使用
union Data{
int i;
float f;
char str[20];
}data;
共用体大小取决于,共用体中最长的那个变量大小
so动态库和编译
比如反编译,安全。
定义:在windows平台和linux平台下都大量存在着库。Android中也存在库,库顾名思义,指的是一个容器文件,里面装的是函数。
由于win和linux的平台不同,主要是编译器,汇编器和连接器不同,因此二者库的二进制是不兼容的。
库存在的意义:库是别人写好现有的,成熟的,可以复用的代码。现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都是从零开始,因此库存在的意义非同寻常。.dll)和静态库(.lib)在安卓平台下动态库(.so)静态库(.a)
动态库和静态库的区别
静态库文件比较大,动态库比较小
静态库需要在编译时被链接在目标代码中,动态库在运行时才会被加载到目标代码中
静态库类似于android中的module,一旦打包APK需要重新编译
动态库类似于jar包,打包是不需要重新进行编译
通过gcc编译动态库,gcc test.c -fPIC -shared -o test.so
通过gcc编译静态库,gcc test.c -fPIC -static -o test.so
二、类的构造和析构、友元函数
构造,类被创建的时候执行
析构,类被销毁的时候执行
友元函数,需要暴露给别人修改本类属性的时候友好
单例模式:
#pragma once
class Student {
private:
static Student* instance;
public:
static Student* getInstance(void);
};
#include "Student.h"
Student* Student::instance = 0;
Student* Student::getInstance(void) {
if (!instance) {//如果等于0,非0就是真,代表instance没有被初始化
instance = new Student();
}
return instance;
}
// Instance.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
#include <iostream>
#include "Student.h"
#include "Test.h"
//操作符重载
int main()
{
Student* student = Student::getInstance();
std::cout << "Hello World!\n";
Test test1;
test1.i = 100;
Test test2;
test2.i = 200;
Test test3 = test1 + test2;
std::cout << test3.i;
}
#pragma once
class Test
{//操作符重载
public:
int i;
Test operator+(const Test& t) {
Test temp;
temp.i = this->i + t.i;
return temp;
}
};
继承多态
静态多态:
编译的时候确认的类型
动态多态:
运行时调用真正对象的函数
虚函数 动态多态,经过virtual修饰。就是虚函数。
注意:构造函数永远不要设为虚函数,析构方法声明为虚函数
#pragma once
class Parent {
public:
virtual void test() {
std::cout << "Parent" << std::endl;
}
};
class Parent1 {
public:
void test() {
std::cout << "Parent1" << std::endl;
}
};
class Child : public Parent,Parent1{
public :
void test() {
//Parent::test();
std::cout << "Child" << std::endl;
}
};
#include <iostream>
#include "Extends.h"
int main()
{
/*Child child;
child.test();*/
Parent* child = new Child();
child->test();
std::cout << "Hello World!\n";
}
泛型编程
#include <iostream>
//泛型模板,模板编程
//函数模板,Java的泛型方法
template <typename T>
T a(T i, T j) {
return i > j ? i : j;
}
//类模板,
template <class T,class E>
class Q {
public:
T test(T t, E e) {
return t + e;
}
};
int main()
{
Q<int, float> q;
std::cout << q.test(1,1.1f);
std::cout << "Hello World!\n";
}
类型转换
C++风格的类型转换提供了4种类型的转换操作来应对不同场合的应用
在C++中const相当于java中的final
强转类型:1、const_cast字面上理解就是去强转const属性。2、static_cast,命名上理解是静态类型强转,如int转char。3、dynamic_cast,命名上理解是动态类型转换,如子类和父类之间的多态类型转换。4、reinterpret_cast,仅仅重新解释类型,但没有进行二进制的转换。
容器
C++中有两种容器,
序列式容器:元素排列顺序与元素本身无关,是由添加顺序所决定的
java中,stack栈。而
c++有 vector,list,dequeue,queue,stack,priority queue;
以vector(向量容器)为例子
//向量容器
vector<int> vec_1;
//声明有一个元素空间
vector<int> vec_2(1);
//6个元素,值都为1
vector<int> vec_3(6, 1);
vector<int> vec_4(vec_3);
vec_1.push_back(100);
cout << "通过下标取得元素:" << vec_1[0] << endl;
vec_1.front();//取得队前
vec_1.back();//取得队尾
//vec_1.clear();//清除
//vec_1.erase(vec_1.begin(), vec_1.end());//清除某一区域的数据
cout << "获得vec的容器大小:" << vec_1.capacity() << endl;
关联式容器:
Set Map
//关联式容器
//set集合元素不可重复
set<int> set1 = { 1,2,3,4,5,10 };
set1.insert(134);//添加
pair<set<int>::iterator, bool> _pair = set1.insert(100);
cout << "set里面有:" << set1.size() << endl;
//cout << "set的pair:" << << endl;
set<int>::iterator itt = set1.begin();
set1.end();//指向最后一个元素的下一个元素
for (; itt != set1.end(); itt++) {
cout << *itt << endl;
}
//map
map<int, string> map1;
map<int, string> map2 = { {1,"E"},{2,"B"} };
map2.insert({ 3,"F" });
map2[3] = "Y";
map<int, string>::iterator mapp = map2.begin();
for (; mapp != map2.end(); mapp++) {
cout << mapp->first<<"=="<<mapp->second << endl;
}
这两种容器都是在stl:标准模板库里面;
命名空间
namespace first_space {
void func() {
cout << "第一个" << endl;
}
}
namespace second_space {
void func() {
cout << "第二个命名空间" << endl;
}
}
int main()
{
//调用第一个
first_space::func();
//调用第二个
second_space::func();
}
引用