一、第一部分
1、C++程序内存分配方式
- 栈区(stack):由编译器自动分配释放,堆区(heap):一般由程序员分配释放,不会随着函数栈的销毁而销毁,有程序员释放,或程序执行完成,有OS回收、全局/静态区( static):全局变量和静态变量的存储,文字常量区:存放常量字符串 5)、程序代码区:存放函数体(类的成员函数、全局函数)的二进制代码
- 栈区是向下生长的,堆区是向上生长的。
- 文字常量区的内容,不能修改,只能读取,局部常量区与全局变量,在内存里的同一区域。
- 对于const 全局常量(放在文字常量区)与const 的局部变量(在函数栈空间)在内存中的,需要明确变量的生命周期。
2、类和对象 (重点掌握)
- 面向对象是一种编程思想,认为现实世界是由对象组成的,对象由相关的数据和操作组成,程序 = 对象 + 对象 + … + 对象
- 类和对象是“一般和特殊”,类的提取:一是特征(属性),另一个是功能(行为)
- 其基本形式如下:
-
- class 类名 {
-
-
- public: 公共成员变量和函数(视它为接口,表示能够对外能够提供的服务)
- protected: 保护成员变量和函数、用于继承
- private: 私有成员变量和函数
- }; //不要漏写了这个分号;
-
//在类内部实现的函数,默认情况下是inline 函数
- 对于类里面的成员,加上一个下划线 eg: char _brand[20}; 用来标示它属于这个类,这是一种编码风格。对于成员函数,有两种实现,类之内实现,和类之外实现。对于private:的成员是私有的,不能再类之外,去直接访问,只能在类之内直接区访问。(private表示的是封装特性)对于,在类之外,只能通过public 的函数区修改它的值,对于struct的不足,都可以直接访问成员,不安全,对于该名字,需要全部替换,对于class,只用修改函数定义的地方该就行了,如果private,其他人是不可见的。
- 对于struct 结构体和类的差别,class的默认访问权限是私有的,而,struct的默认访问权限是共有的(public的)
- protected 关键字,在类之外也是不能直接使用,在继承处多使用,交给派生类区使用。
- 当在类外部去实现函数是,要在函数名前加上类名,作为作用域,eg: void computer: setprice( );
- C++为类提供了两种特殊的成员函数--构造函数、析构函数来完成,实现对数据成员的初始化。
- 构造函数,在对象创建时自动调用,用以完成对象成员变量等的初始化及其他操作(如为指针成员动态申请内存空间等);如果程序员没有显式的定义它,系统会提供一个默认的构造函数。函数的名字与类名相同,没有返回类型和返回值,即使是void也不能有。创建对象时也可以省略参数。
- 析构函数,在对象撤销时自动调用,用以执行一些清理工作的,如释放成员函数中动态申请的内存等。如果程序员没有显式的定义它,系统也会提供一个默认的析构函数。以波浪号开头,没有 没有返回类型,也不能指定参数,因此,析构函数只能有一个,不能被重载。
-
- 如果没有显示定义一个析构函数,系统便会默认提供。
- 当自己定义一个有参构造函数时,系统便不会提供默认的无参构造函数了。此时,如果还希望能够调用默认构造函数创造对象,则必须自己显式定义默认的构造函数。说明构造函数是可以实现重载的
- 初始化表达式(列表)、只要将成员初始化表达式放在构造函数的头和体之间,并用冒号将其与构造函数的头分隔开,便可实现数据成员表中元素的初始化 。
Point
: _ix(0) //建议一行初始化一个元素的写法。
,_iy(0) //初始化表达式(列表)初始化顺序只跟元素在类中被声明的顺序有关,并不是有初始化列表的顺序进行的。
{
cout<<_ix<<_iy;
}
游戏引擎,(前端方面) cocos2dx 触控科技,可以阅读源码。纯C++实现,C++ 11标准
二、第二部分
- 对于直接copy 指针首地址,叫浅拷贝,先开辟空间,在copy叫深拷贝。
- 对于栈对象而言,当其生命周期结束时,就会自动调用析构函数。析构函数可以被显式调用的,但一般是不推荐这样使用的。而对于堆空间,new出来的空间(Com *pc2=new Com()),我们就需要手动去释放。delete pc2 。对于全局变量和局部变量,会在函数结束后在默认调用析构函数。
- 复制构造函数。(重点)C++中经常使用一个常量或变量初始化另一个变量,对于类也是可以的,以point类为例: point pt1(2,3); point pt2=pt1; 或者point pt2( pt1); //因为系统默认的提供了一个复制构造函数。如:point:: point (const point &); 当系统默认提供的复制构造函数不能满足需求时,只能自己去定义复制构造函数。 ---首先 复制构造函数的引用符号&不能少,否则在调用复制构造函数会导致无穷递归,直到栈溢出,---其次,它的const 关键字也不能去掉。如果去掉,右值形式存在的对象无法进行传参。匿名对象--->存在时间非常短,也是右值// const Point rhs=rfs ;是不行的。
- 复制构造函数调用机制
- 当把一个已经存在的对象赋值给另一个新的对象时。
- 当实参和形参都是对象,进行形参和实参的结合时。
- 当函数的返回值是对象,函数调用完成返回时。( 但编译器会优化,默认是看不到的,可以加上 -fno-elide-constructors编译选项,查看)
g++ point.cc -fno-elide-constructors
5、赋值运算符 =
- 成员函数形式的运算符声明和实现与成员函数类似,首先应当在类定义中声明该运算符,
-
- 如果没有提供赋值运算符函数,系统会默认提供一个赋值运算符函数。 形式: Point & operator=(const Point & rhs) 在类之内定义时,形式为: 声明的具体形式: 返回类型 operator 运算符(参数列表);
- 当在类之外去定义赋值运算符时,形式为:返回类型 类名::operator 运算符(参数列表)
- --> * this指针指向当前对象本身,是第一个隐含的this指针,形式为 Point *const this ;operator= 是一个函数名。c1= c3 等价于 c1.operator = (c3 )
- 1、对于自赋值问题,2、回收右操作数 的空间 3、在去进行深拷贝
- 注意:左操作数就是在数据的左边去操作数据。同理,右操作数。
- 特殊数据成员的初始化
-
- 对于const 数据成员只能在初始化列表去初始化。
- 对于引用数据成员也只能在初始化列表去初始化。
- 对象成员在传参时,也应该放在初始化列表之中初始化,尽量。
- 静态数据成员由该类的所有对象共享。静态数据成员的初始化必须在类申明之外进行,且不再包含static关键字,格式如下:
-
- 类型 类名::变量名 = 初始化表达式; //普通变量 类型 类名::对象名(构造参数); //对象变量
- 如float computer::total_price = 0; //在全局区。
- 特殊函数成员
-
- 静态成员函数体内不能访问使用非静态的成员变量和非静态的成员函数;只能调用静态成员数据和函数 --->因为静态成员函数的参数列表中不含有this指针
- 若果没要访问,只有通过传参数了(const Computer & com) ,静态成员函数直接通过类名进行访问。
- const成员函数 ,const关键字放在函数的参数表和函数体之间,称为const成员函数
-
- eg:void print() const
- 其作用是将
void print() const => void print( const
Point * const this) const
-
-
- const对象只能调用const 版本的成员函数
- 非const对象是可以调用const 版本的成员函数的。
- 如果两个成员函数同时出现,则两个不同的对象各自调用自己的成员函数
-
- 程序在结束的时候,系统会自动析构所有的全局变量。事实上,系统也会析构所有的类的静态成员变量,就像这些静态成员也是全局变量一样。
- 对于空的对象时,其大小不是0,为了取地址,必须给他一个空间,故它占一个空间。
- 对于cout来说,cout对象不能输出空指针,否则程序就会可能不会正常运行。对于类型不同的类来说,当使用赋值运算符时,会有隐式转换,--> eg : Point pt=1; 若不希望发生隐式转换,则加上 explicit关键字,显示转换禁止隐式转换。
- 如果用数组来实现队列,使用头尾指针
-
- 队列为空: front == rear
- 队列已满: (rear + 1)% size == front
- 往队列中添加元素: arr[ rear++] = val ; rear % =size 此时我们假设全满是队列元素减一,即留下一个不放。
- 从队列取出元素: ++ front ; front % = size ;
- 获取对头元素: return arr [ front];
- 获取队尾元素return arr [ (rear -1 +size) % size]