1.using namespace std 告诉编译器使用 std 命名空间。命名空间是 C++ 中一个相对新的概念
2. g++ a.cpp 生成a.out 可以直接 ./a.out执行
3.三字符表
三字符组 | 替换 |
---|---|
??= | # |
??/ | \ |
??’ | ^ |
??( | [ |
??) | ] |
??! | | |
??< | { |
??> | } |
??- | ~ |
4.explicit构造函数是用来防止隐式转换的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
class Test1 { public: Test1(int n) { num=n; } private: int num; }; class Test2 { public: explicit Test2(int n) { num=n; }//explicit(显式)构造函数 private: int num; }; int main() { Test1 t1=12;//隐式调用其构造函数,成功 Test2 t2=12;//编译错误,不能隐式调用其构造函数 Test2 t2(12);//显式调用成功 return 0; } |
5.std命名空间, 假设你不使用预处理 using namespace std;就要加上 std::String . 如果加上了using namespace std,可以直接String
6.lambda ([=]:是将外部所有的变量 copy一份, [&]: 引用外部变量 同一地址)
- []:默认不捕获任何变量;
- [=]:默认以值捕获所有变量;
- [&]:默认以引用捕获所有变量;
- [x]:仅以值捕获x,其它变量不捕获;
- [&x]:仅以引用捕获x,其它变量不捕获;
- [=, &x]:默认以值捕获所有变量,但是x是例外,通过引用捕获;
- [&, x]:默认以引用捕获所有变量,但是x是例外,通过值捕获;
- [this]:通过引用捕获当前对象(其实是复制指针);
- [*this]:通过传值方式捕获当前对象;
1 2 3 4 |
int age = 26; auto labFun = [=](int x, int y) -> int { return age+x+y; }; int ala = labFun(1,2); cout << ala << endl; |
1 2 3 4 5 |
int age = 26; auto labFun = [&](int x, int y) -> int { return age+x+y; }; age = 27; int ala = labFun(1,2); cout << ala << endl; // 30 |
1 2 3 4 5 |
int age = 26; auto labFun = [=,&age](int x, int y) -> int { return age+x+y; }; age = 27; int ala = labFun(1,2); cout << ala << endl; // 30 |
捕获this
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
#include <iostream> using namespace std; class test { public: void hello() { cout << "test hello!n"; }; void lambda() { auto fun = [this]{ // 捕获了 this 指针 this->hello(); // 这里 this 调用的就是 class test 的对象了 }; fun(); } }; int main() { test t; t.lambda(); } |
7.随机数
1 2 |
srand( (unsigned)time(NULL) ); cout << rand() << endl; |
8.setw格式化输出(空格)
1 2 3 4 |
#include <iomanip> using std::setw; cout << "Element" << setw( 6 ) << "Value" << endl; |
9.strcmp代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
int strcmp(const char *str1,const char *str2) { while(*str1 == *str2) { if(*str1 == '\0') { return 0; } str1++; str2++; } cout << "str1=" << *str1 << " str2=" << *str2 << endl; return *str1 - *str2; } |
10.引用
1 2 3 4 5 6 7 8 9 10 11 12 13 |
void quoteSomePoint(int &a, int &b) { a = 11; b = 22; cout<< &a << " :: " << &b<< endl; } int main() { int a=10, b=20; quoteSomePoint(a,b); } |
11. struck
1 2 3 4 5 6 7 |
void printStrBook(Books book) { cout << "2222222" << book.title << "point=" << &book<< endl; } Books book; strcpy(book.title, "sdklksd"); |
12.函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#.hpp class Person { public: char name[16]; char address[33]; void didload(); }; #.cpp void Person::didload() { Person person; strcpy(person.name, "张三"); strcpy(person.address, "北京"); printf("person.name=%s, person.address=%s",person.name,person.address); } |
- :: 叫作用域区分符,指明一个函数属于哪个类或一个数据属于哪个类。
- :: 可以不跟类名,表示全局数据或全局函数(即非成员函数)
*构造函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#.hpp class Person { public: Person(); Person(int age); }; #.cpp /** 构造函数 */ Person::Person(void) { printf("Person 构造函数开始"); } /** 带参数构造函数*/ Person::Person(int age) { printf("age=%d",age); } |
1 2 3 4 5 6 7 8 9 10 11 12 |
#.hpp class Cat { public: int m_x; Cat(int a); }; #.cpp Cat::Cat(int a):m_x(a) { printf("cat a=%d,mx=%d",a,m_x); } |
13.友元 friend
在一个.h中有些函数指定特定的类可以调用, 其他类不能调用
- 友元关系不能传递
- 友元关系是单向的
- 友元关系不能被继承
1 2 3 4 5 6 7 |
class Cat { public: friend Person; private: char name[22]; # name是private,只有在Person中可以调用 }; |
14. 内联inline函数
内联能提高函数的执行效率,但是他是在调用的时候copy代码 导致代码量和内存增加,要慎用!
不可用的情况:
- 函数代码比较长,导致代码过大
- 函数内循环或者其他复杂的控制结构,那么执行函数体内代码时间比函数调用开销大多,因此内联意义不大
编译器一般选择短小而简单的函数来内联
现代处理器由于更好的利用了指令缓存, 小巧的代码往往执行更快。
目的是为了解决程序中函数调用的效率问题,解决一些频繁调用的小函数大量消耗栈空间(栈内存)的问题,在系统下,栈空间是有限的,假如频繁大量的使用就会造成因栈空间不足而导致程序出错的问题,并不是说声明了内联就会内联,声明内联只是一个建议而已。
15.static
1 2 3 4 5 6 7 8 9 |
class Box { public: static int objectCount; } // 初始化类 Box 的静态成员 int Box::objectCount = 0; cout << "Total objects: " << Box::objectCount << endl; |
16.copy构造函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
Line::Line (int len) { printf("构造\n"); ptr = new int; *ptr = len; } Line::Line (const Line &obj) { printf("copy构造\n"); ptr = new int ; *ptr = *obj.ptr; } Line::~Line() { printf("释放 = %p add=%d \n",this,add); delete ptr; } |
Line line(9);
Line linea = line; 这一步会调用copy构造函数
17.inline
内联函数的目的是为了解决程序中函数调用的效率问题,这么说吧,程序在编译时,编译器将程序中出现的内联函数的调用表达式用内联函数的函数体进行替换,而对于其他的函数,都是在运行时候才被替代(空间换时间)。
- 在内联函数内不允许使用循环语句和开关语句
- 在使用前定义
- 类中内部定义的函数是内联函数(有些函数即使声明为内联的也不一定会被编译器内联, 这点很重要; 比如虚函数和递归函数就不会被正常内联.)
定义: 当函数被声明为内联函数之后, 编译器会将其内联展开, 而不是按通常的函数调用机制进行调用.
优点: 当函数体比较小的时候, 内联该函数可以令目标代码更加高效. 对于存取函数以及其它函数体比较短, 性能关键的函数, 鼓励使用内联.
缺点: 滥用内联将导致程序变慢. 内联可能使目标代码量或增或减, 这取决于内联函数的大小. 内联非常短小的存取函数通常会减少代码大小, 但内联一个相当大的函数将戏剧性的增加代码大小. 现代处理器由于更好的利用了指令缓存, 小巧的代码往往执行更快
18.static
静态变量
1 2 3 4 5 6 7 8 9 10 |
class StDor { static int age; void run() { printf("run"); } }; int StDor::age = 11; |
静态函数
1 2 3 4 5 6 7 8 9 10 11 |
class StDor { static int getCount() { return 11; } } int main(void) { StDor::getCount(); } |
19.继承
1 2 3 |
class cat: public Animal, public other { } |
20.重载
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
double Box::getVolume(void) { return width * height; } void Box::setWidth(double w) { width = w; } void Box::setHeight(double h) { height = h; } // 重载 + 运算符,用于把两个 Box 对象相加 Box Box::operator*(const Box& b) { Box box; box.width = this->width + b.width; box.height = this->height + b.height; return box; } // 使用 Box box1; Box box2; box1.width = 3; box1.height = 4; box2.width = 5; box2.height = 6; double sum1 = box1.getVolume(); double sum2 = box2.getVolume(); Box b = box1 * box2; printf("sum1=%f, sum2=%f, b.width=%f,b.height=%f",sum1,sum2,b.width,b.height); |
双目算术运算符 | + (加),-(减),*(乘),/(除),% (取模) |
关系运算符 | ==(等于),!= (不等于),< (小于),> (大于>,<=(小于等于),>=(大于等于) |
逻辑运算符 | ||(逻辑或),&&(逻辑与),!(逻辑非) |
单目运算符 | + (正),-(负),*(指针),&(取地址) |
自增自减运算符 | ++(自增),–(自减) |
位运算符 | | (按位或),& (按位与),~(按位取反),^(按位异或),,<< (左移),>>(右移) |
赋值运算符 | =, +=, -=, *=, /= , % = , &=, |=, ^=, <<=, >>= |
空间申请与释放 | new, delete, new[ ] , delete[] |
其他运算符 | ()(函数调用),->(成员访问),,(逗号),[](下标) |
不可重载的运算符列表:
- .:成员访问运算符
- .*, ->*:成员指针访问运算符
- :::域运算符
- sizeof:长度运算符
- ?::条件运算符
- #: 预处理符号
21.三维数组创建和释放
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
int ***array; // 假定数组第一维为 m, 第二维为 n, 第三维为h // 动态分配空间 array = new int **[m]; for( int i=0; i<m; i++ ) { array[i] = new int *[n]; for( int j=0; j<n; j++ ) { array[i][j] = new int [h]; } } //释放 for( int i=0; i<m; i++ ) { for( int j=0; j<n; j++ ) { delete array[i][j]; } delete array[i]; } delete [] array; |
22.数组创建和释放
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#include <iostream> using namespace std; class Box { public: Box() { cout << "调用构造函数!" <<endl; } ~Box() { cout << "调用析构函数!" <<endl; } }; int main( ) { Box* myBoxArray = new Box[4]; delete [] myBoxArray; // 删除数组 return 0; } |
23.数组的释放
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
class A { private: char *m_cBuffer; int m_nLen; public: A(){ m_cBuffer = new char[m_nLen]; } ~A() { delete [] m_cBuffer; } }; A *a = new A[10]; // 仅释放了a指针指向的全部内存空间 但是只调用了a[0]对象的析构函数 剩下的从a[1]到a[9]这9个用户自行分配的m_cBuffer对应内存空间将不能释放 从而造成内存泄漏 delete a; // 调用使用类对象的析构函数释放用户自己分配内存空间并且 释放了a指针指向的全部内存空间 delete [] a; |
24.自定义命名空间
1 2 3 4 5 6 7 8 9 10 11 |
namespace FNameSpace { void run(void) { printf("run -------"); } } FNameSpace::run(); #在别的类中调用用using using namespace FNameSpace; |
嵌套命名空间
1 2 3 4 5 6 7 8 9 10 11 12 13 |
namespace namespace_name1 { // 代码声明 namespace namespace_name2 { // 代码声明 } } #使用 <span class="hl-comment">// 访问 namespace_name2 中的成员 </span> <span class="hl-reserved">using</span> <span class="hl-types">namespace</span> <span class="hl-identifier">namespace_name1</span><span class="hl-code">::</span><span class="hl-identifier">namespace_name2</span><span class="hl-code">; </span><span class="hl-comment">// 访问 namespace:name1 中的成员</span> <span class="hl-reserved">using</span> <span class="hl-types">namespace</span> <span class="hl-identifier">namespace_name1</span><span class="hl-code">;</span> |
25.泛型
1 2 3 4 5 |
template <typename T> inline T const& Max (T const& a, T const& b) { return a < b ? b:a; } |
26.预处理宏 #define是替换 gcc -E hello.cpp > hello
1 2 3 4 |
#define MKSTR( x ) #x MKSTR(文集) #define CONCAT( x, y ) x ## y count << CONCAT(a,b); 相当于cout << ab |
问题:
1.这个指针地址 和fn不一致, ins[] 形参做了什么??
2.2.delete[] arr; 在后面使用会有什么问题? 如何避免?
delete是释放了对一块内存的使用权,但可能被别的使用并修改或者被回收,(释放后arr指针依然存在的,还是指向那个未知内存)如果delete后在使用可能会造成野指针,或者结果改变。 delete后最好把指针指向NULL,不用管那块内存什么情况,在后面使用是判断是否为NULL来处理(delete后不应该再使用了,可能有复杂情况下)(和操作系统也有一定关系,何时回收)
3.如果自由存储区已被用完,可能无法成功分配内存。所以建议检查 new 运算符是否返回 NULL 指针(new 与 malloc() 函数相比,其主要的优点是,new 不只是分配了内存,它还创建了对象。)
1 2 3 4 5 6 7 |
double* pvalue = NULL; if( !(pvalue = new double )) { cout << "Error: out of memory." <<endl; exit(1); } |
4.new malloc区别?
new是分配内存并创建对象(走默认的构造函数),malloc只是在堆上分内存 要强制转换成对象(不走默认的构造函数)
1 2 3 4 5 6 7 8 |
// 用malloc()函数在堆区分配一块内存空间,然后用强制类型转换将该块内存空间 // 解释为是一个TEST类对象,这不会调用TEST的默认构造函数 TEST * pObj1 = (TEST *)malloc(sizeof(TEST)); pObj1->Print(); // 用new在堆区创建一个TEST类的对象,这会调用TEST类的默认构造函数 TEST * pObj2 = new TEST; pObj2->Print(); |
5.