安卓NDK开发-C++笔记

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();
}

引用

发布了22 篇原创文章 · 获赞 4 · 访问量 4330

猜你喜欢

转载自blog.csdn.net/qq_38366111/article/details/101694498