美文网首页c++
c++学习笔记——第二天

c++学习笔记——第二天

作者: 我就是一个垃圾 | 来源:发表于2019-02-13 19:15 被阅读1次

1、c++中的内存管理

C语言提供了malloc和free两个函数(库函数)实现,完成对内存的释放和申请,而c++中提供了两个关键字new和delete(关键字)。

能用malloc和free实现的都能用new和delete实现,而new和delete实现的用malloc和free不一定能实现

new/new[]用法:

1.开辟单变量地址空间

int *p = new int; //开辟大小为 sizeof(int)空间

int *a = new int(5); //开辟大小为 sizeof(int)空间,并初始化为 5

2.开辟数组空间

一维:

 int *a = new int[100]{0};开辟一个大小为 100 的整型数组空间

int **p = new int*[5]{NULL}

二维: int (*a)[6] = new int[5][6]

三维: int (*a)[5][6] = new int[3][5][6]

四维维及其以上:依此类推.

delete /delete[]用法:

1. int *a = new int;

delete a; //释放单个 int 的空间

2.int *a = new int[5];

delete []a; //释放 int 数组空间

不管几维空间,都是delete []a;只有一个【】

关于返回值

int main()

{

//c语言版本

char *ps = (char*)malloc(100);

if(ps == NULL)

return -1;

//C++内存申请失败会抛出异常

try{

int *p = new int[10];

}catch(const std::bad_alloc e) {

return -1;

}

//C++内存申请失败不抛出异常版本

int *q = new (std::nothrow)int[10];

if(q == NULL)

return -1;

return 0;

}

注意事项

1,new/delete 是关键字,效率高于 malloc 和 free.

2,配对使用,避免内存泄漏和多重释放。

3,避免,交叉使用。比如 malloc 申请的空间去 delete,new 出的空间被 free更进一步

如果只是上两步的功能,c 中的 malloc 和 free 完全可以胜任,C++就没有必要更进一

步,引入这两个关键字。

此两关键字,重点用在

类对像的申请与释放。申请的时候会调用构造器完成初始化,释

放的时候,会调用析构器完成内存的清理。以后我们会重点讲

二、内联函数(inline function)

内联

c 语言中有宏函数的概念。宏函数的特点是内嵌到调用代码中去,避免了函数调用的开销。但是由于宏函数的处理发生在预处理阶段,缺失了语法检测和有可能带来的语意差错。

优点:避免调用时的额外开销(入栈与出栈操作)

代价:由于内联函数的函数体在代码段中会出现多个“副本”,因此会增加代码段的空间。

本质:以牺牲代码段空间为代价,提高程序的运行时间的效率。

适用场景:函数体很“小”,且被“频繁”调用。

适用于函数只有几行的代码量来使用

宏定义是在预处理阶段进行展开的,而内联函数是在编译阶段进行展开

三、类型强转(type cast)

类型转换有 c 风格的,当然还有 c++风格的。c 风格的转换的格式很简单(TYPE  EXPRESSION),但是 c 风格的类型转换有不少的缺点,有的时候用 c 风格的转换是不合适的,因为它可以在任意类型之间转换,比如你可以把一个指向 const 对象的指针转换成指向非const 对象的指针,把一个指向基类对象的指针转换成指向一个派生类对象的指针,这两种转换之间的差别是巨大的,但是传统的 c 语言风格的类型转换没有区分这些。还有一个缺点就是,c 风格的转换不容易查找,他由一个括号加上一个标识符组成,而这样的东西在 c++程序里一大堆。所以 c++为了克服这些缺点,引进了 4 新的类型转换操作符。

1.静态类型转换:

语法格式:

static_cast<目标类型> (标识符)

转化规则:

在一个方向上可以作隐式转换,在另外一个方向上就可以作静态转换。

int a = 10;

int b = 3;

cout<<(a)/b<<endl; //float = int int = float

return 0;

int *p; void *q;

p = static_cast(q);

char *p = static_cast(malloc(100));

重解释类型转换:

语法格式:

reinterpret_cast<目标类型> (标识符)

转化规则

“通常为操作数的位模式提供较低层的重新解释”也就是说将数据以二进制存在形式

的重新解释,在双方向上都不可以隐式类型转换的,则需要重解释类型转换。

char *p; int *q;

p = q;

q = p;

int main()

{

int x = 0x12345648;

char *p = reinterpret_cast(&x);

//char*p = static_cast(&x);

printf("%x\n",*p);

int a[5] = {1,2,3,4,5};

int *q = reinterpret_cast((reinterpret_cast(a) +1));

printf("%x\n",*q);

return 0;

}

(脱)常类型转换:

语法格式:

const_cast<目标类型> (标识符) //目标类类型只能是指针或引用。

语法规则

用来移除对象的常量性(cast away the constness)使用 const_cast 去除 const 限定的

目的不是为了修改它的内容,使用 const_cast 去除 const 限定,通常是为了函数能够接受

这个实际参数。

应用场景 1:

#include

using namespace std;

void func(int & ref) //

别人己经写好的程序或类库

{

cout<<ref<<endl;

}

int main(void)

{

const int m = 4444;

func(const_cast(m));

return 0;

}

脱掉 const 后的引用或指针可以改吗?

#include

using namespace std;

int main()

{

const int x = 200;

int & a =const_cast(x); // int &a = x;

a = 300;

cout<<a<<x<<endl;

cout<<&a<<"---"<<&x<<endl;

int *p =const_cast(&x); // int *p = &x;

*p = 400;

cout<<a<<*p<<endl;

cout<<p<<"---"<<&x<<endl;

struct A

{

int data;

};

const A xx = {1111};

A &a1 = const_cast< A&>(xx);

a1.data = 222;

cout<<a1.data<<xx.data<<endl;

A *p1 = const_cast(&xx);

p1->data = 333;

cout<<p1->data<<xx.data<<endl;

return 0;

}

结论:

不要去试图改变const的值

可以改变 const 自定义类的成员变量,但是对于内置数据类型,却表现未定义行为.

Depending on the type of the referenced object, a write operation throu

gh the resulting pointer, reference, or pointer to data member might pr

oduce undefined behavior.

const 常变量(补充):

C++中 const 定义的变量称为常变量。变量的形式,常量的作用,用作常量,常用于

取代#define 宏常量。

#include

using namespace std;

#define N 200

int main()

{

const int a = 200;

int b = 300;

int c = a +b; //int c = N + b;

return 0;

}

动态类型转换:

语法格式:

dynamic_cast<目标类型> (标识符)

用于多态中的父子类之间的强制转化,以后再讲。

四、命名空间(namespace scope) 

为什么要引入namespace命名空间为了大型项目开发,而引入的一种避免命名冲突的一种机制。比如说,在一个大型项目中,要用到多家软件开发商提供的类库。在事先没有约定的情况下,两套类库可能在存在同名的函数或是全局变量而产生冲突。项目越大,用到的类库越多,开发人员越多, 这种冲突就会越明显。

语法规则

NameSpace 是对全局(Global scope)区域的再次划分。

声明

命令空间的声明及 namespace 中可以包含的内容

namespace NAMESPACE

{

全局变量 int a;

数据类型 struct Stu{};

函数 void func();

其它命名空间 namespace

}

使用方法

1.直接指定 命名空间: Space::a = 5;

2.使用 using+命名空间+空间元素:using Space::a; a = 2000;

3.使用 using +namespace+命名空间: using namespace Space;

无可辟免的冲突 

#include

using namespace std;

namespace Space

{

int x;

}

namespace Other

{

int x;

}

int main()

{

// Space::x = 4;

// cout<<Space::x<<endl;

// Other::x = 5;

//cout<<Other::x<<endl;

{

using Space::x;

x = 5;

cout<<x<<endl;

{

using Other::x;

x = 7;

cout<<x<<endl;

}

 {

using namespace Space;

x = 5;

{

using namespace Other;

x = 8;

}

return 0;

}

命名空间还支持嵌套

#include

using namespace std;

namespace MySpace

{

int x = 1;

int y = 2;

namespace Other {

int m = 3;

int n = 4;

}

}

int main()

{

using namespace MySpace::Other;

cout<<m<<n<<endl;

return 0;

两个相同的命名空间会自动合并成一个命名空间,std是标准命名空间

协作开发

同名命名空间自动合并,对于一个命名空间中的类,要包含声明和实现。

a.h

#ifndef A_H

#define A_H

namespace XX {

class A

{

public:

A();

~A();

};

}

#endif // A_H

a.cpp

#include "a.h"

using namespace XXX

{

A::A()

{}

A::~A()

{}

}

b.h

#ifndef B_H

#define B_H

namespace XX

{

class B

{

public:

B();

~B();

};

}

#endif // B_H

b.cpp

#include "b.h"

namespace XX {

B::B()

{}

B::~B()

{} }

main.cpp

#include

#include "a.h"

#include "b.h"

using namespace std;

using namespace XX;

int main()

{

A a;

B b;

return 0;

}

五、系统 string 类

头文件在程序中使用string类型,必须包含头文件 <string>。      #include <string> //注意这里不是string.h,string.h是C字符串头文件。


定义及初始化

int main()

{

string str;

str = "china";

string str2 = " is great ";

string str3 = str2;

cout<<str<<str2<<endl<<str3<<endl;

return 0;

}

类型大小

cout<<"sizeof(string) = "<<sizeof(string)<<endl;

cout<<"sizeof(str) = "<<sizeof(str)<<endl;

常用运算

赋值

string str3 = str2;

加法

string combine = str + str2;

cout<<combine<<endl;

关系

string s1 = "abcdeg";

string s2 = "12345";

if(s1>s2)

cout<<"s1>s2"<<endl;

else

cout<<"s1<s2"<<endl;

string s3 = s1-s2;

cout<<s3<<endl;

string 类型数组

string sArray[10] = {

"0",

"1",

"22",

"333",

"4444",

"55555",

"666666",

"7777777",

"88888888",

"999999999",

};

for(int i=0; i<10; i++)

{

cout<<sArray[i]<<endl;

}

string 数组是高效的,如果用二维数组来存入字符串数组的话,则容易浪费空间,此时列数是由最长的字符串决定。如果用二级指针申请堆空间,依据大小申请相应的空间,虽然解决了内存浪费的问题,但是操作麻烦。用 string 数组存储,字符串数组的话,效率即高又灵活。

相关文章

网友评论

    本文标题:c++学习笔记——第二天

    本文链接:https://www.haomeiwen.com/subject/xannsqtx.html