1.
全局变量,局部变量,静态变量
auto,register《没用》 extern全局使用会引出错误
static 直到全部结束才释放
2.概念
2.1 全局数据区:全局变量/常变量,静态变量,字符串常量
2.2 代码区:函数和程序代码
2.3 栈:行参,返回地址,局部变量
2.4 堆:动态分配内存
分配空间
2.1
全局常变量->全局变量->局部静态变量 从低地址向高地址分配 运行结束后收回,顺序与分配一致
2.2
为各个函数调用执行代码时在代码段分配空间,然后将代码调入内存,按函数定义的次序排列
2.3
按照 行参->返回地址->局部变量 依次入栈 按“栈”收回
3
3.1 函数原型作用域 fun(int i, int j);只能作用于两括号之间的区域
3.2 块作用域 每个括号括起来的为单独块作用于互不影响
for(int i = 4; i < 5; cout<<"L6: i = "<<i<<endl; i++) { cout<<"L4: i = "<<i<<endl; int i=5; i++; cout<<"L5: i = "<<i<<endl; } L4: i=4 L5: i=6 L6: i=4
3.3 文件作用域 全局变量,函数,常量 从文件申明点到文件尾
---作用域从外到内,从前到后,可见性从内向外,从后向前
4
预处理指令:在编译前由预处理器执行,在目标程序中不含预处理指令对应的机器码,因此无分号
#include命令把.h .c .cpp文件内容全部包含进来,宏名 宏替换 带参数宏
5
条件编译# if ~#endif
#ifdef~ #endif
#ifndef ~ #endif
6
名字空间:对相同标识符相同名字放在不同空间内,利用名字空间对标志符常量,变量,函数,对象和类进行分组,防止命名冲突
个别使用申明:N::M
全局申明个别成员:以上两个为自己定义的名字空间 using N::M
全局申明方式:using namespace std;c++标准库名字空间std cout,cin 均来自std;
第七章
1.c语言 c++前六章为面向过程的设计
2.面向对象的程序模块由类构成的,是对逻辑上相关的函数与数据的封装,对问题的抽象描述
3.
class 类名 { public: protected: private: } //控制属性(访问权限)
4.类:类名标志符,包括对象即属性,函数即方法
4.1 类知识一种类型,在定义的时候不能给成员变量赋初值
可以使用以定义完整的类
不能定义不能定义完整的类的变量,可以定义该类的指针和引用成员
类外定义函数体 返回值类型 类名::成员函数名(行参表)+inline后和类中函数一样作用
在类中的方法可以定义该类定义的变量(对象)通过变量使用成员
类的封装也限制类的成员其访问范围在类的作用域中
4.2
用类创建多个对象,只为初始化的各属性分配内存,而其成员函数为共享。
外函数体在类内申明还是属于类内,可以对类的成员属性进行操作
在类中的方法可以定义该类定义的变量(对象)通过变量使用成员,也可以对类属性进行操作。包括private
4.3
构造函数:自动调用
析构函数:自动调用 ~逻辑非 逆构造函数
无参数,不能重载,一个类只用一个,无返回值,~,无定义则默认无作用的析构函数
局部变量在栈中建立,建立与消失顺序相反--析构函数会显示。全局变量一样,不会显示,因为程序已经结束。
拷贝构造函数
浅拷贝 深拷贝:如果一个类拥有资源,当这个类的对象发生复制过程的时候,资源重新分配,这个就是深拷贝,反之,没有重新分配资源,就是浅拷贝。
对于普通类型的对象来说,它们之间的复制是很简单的,例如:
int a=88;
int b=a;
而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量。下面看一个类对象拷贝的简单例子。
using namespace std;
class CExample { private: int a; public: CExample(int b) { a=b;} void Show () { cout<<a<<endl; } }; int main() { CExample A(100); CExample B=A; B.Show (); return 0; }
运行程序,屏幕输出100。从以上代码的运行结果可以看出,系统为对象B分配了内存并完成了与对象A的复制过程。就类对象而言,相同类型的类对象是通过拷贝构造函数来完成整个复制过程的。下面举例说明拷贝构造函数的工作过程。
#include <iostream> using namespace std; class CExample { private: int a; public: CExample(int b) { a=b;} CExample(const CExample& C) { a=C.a; } void Show () { cout<<a<<endl; } }; int main() { CExample A(100); CExample B=A; B.Show (); return 0; }
CExample(const CExample& C)就是我们自定义的拷贝构造函数。可见,拷贝构造函数是一种特殊的构造函数,函数的名称必须和类名称一致,它的唯一的一个参数是本类型的一个引用变量,该参数是const类型,不可变的。例如:类X的拷贝构造函数的形式为X(X& x)。
当用一个已初始化过了的自定义类类型对象去初始化另一个新构造的对象的时候,拷贝构造函数就会被自动调用。也就是说,当类的对象需要拷贝时,拷贝构造函数将会被调用。以下情况都会调用拷贝构造函数:
一个对象以值传递的方式传入函数体
一个对象以值传递的方式从函数返回
一个对象需要通过另外一个对象进行初始化。
如果在类中没有显式地声明一个拷贝构造函数,那么,编译器将会自动生成一个默认的拷贝构造函数,该构造函数完成对象之间的位拷贝。位拷贝又称浅拷贝,后面将进行说明。
自定义拷贝构造函数是一种良好的编程风格,它可以阻止编译器形成默认的拷贝构造函数,提高源码效率。
浅拷贝和深拷贝
在某些状况下,类内成员变量需要动态开辟堆内存,如果实行位拷贝,也就是把对象里的值完全复制给另一个对象,如A=B。这时,如果B中有一个成员变量指针已经申请了内存,那A中的那个成员变量也指向同一块内存。这就出现了问题:当B把内存释放了(如:析构),这时A内的指针就是野指针了,出现运行错误。
深拷贝和浅拷贝可以简单理解为:如果一个类拥有资源,当这个类的对象发生复制过程的时候,资源重新分配,这个过程就是深拷贝,反之,没有重新分配资源,就是浅拷贝。下面举个深拷贝的例子。
#include <iostream> using namespace std; class CA { public: CA(int b,char* cstr) { a=b; str=new char[b]; strcpy(str,cstr); } CA(const CA& C) { a=C.a; str=new char[a]; //深拷贝 if(str!=0) strcpy(str,C.str); } void Show() { cout<<str<<endl; } ~CA() { delete str; } private: int a; char *str; }; int main() { CA A(10,"Hello!"); CA B=A; B.Show(); return 0; }
深拷贝和浅拷贝的定义可以简单理解成:如果一个类拥有资源(堆,或者是其它系统资源),当这个类的对象发生复制过程的时候,这个过程就可以叫做深拷贝,反之对象存在资源,但复制过程并未复制资源的情况视为浅拷贝。
浅拷贝资源后在释放资源的时候会产生资源归属不清的情况导致程序运行出错。
Test(Test &c_t)是自定义的拷贝构造函数,拷贝构造函数的名称必须与类名称一致,函数的形式参数是本类型的一个引用变量,且必须是引用。
当用一个已经初始化过了的自定义类类型对象去初始化另一个新构造的对象的时候,拷贝构造函数就会被自动调用,如果你没有自定义拷贝构造函数的时候,系统将会提供给一个默认的拷贝构造函数来完成这个过程,上面代码的复制核心语句就是通过Test(Test &c_t)拷贝构造函数内的p1=c_t.p1;语句完成的。
6.
对象指针
效率高,传递地址 Clock *p; Clock C1(8,0,0) p=&C1; p->ShowTime();
对象引用
一定要初始化(除非作为函数参数或者返回值), Clock& Cr=C1; Cr.ShowTime();
对象数组 Clock Clock1[2]={Score(2016,"Beijing",80,90)} ;
7
组合类,初始化,权限,
静态成员
类:成员(实例/实例属性)
类属性:由static实现 static 数据类型 静态数据成员名
数据类型 类名::静态数据成员名=初始值;//静态生存期
在类内任意存取,在类外通过类和对象访问权限为public的成员
可以通过成员函数访问
static成员函数
可以存取静态数据成员,传递对象参数访问实例成员
只有一个拷贝,所以没有this指针
和普通成员函数一样属性,通过类名和对象名访问要考虑属性。
友元类/函数
可以访问限制成员,兼顾封装性
不属于任何类,不能通过类引用。
在类内申明,类外定义不加类申明。
友元不具有传递性
单向
class B; class A{ public: void funA(B b); }; class B{ public: void funB(A a); }; //前向引用申明
8
常成员与常对象
const Clock C1(9,9,9)
Clock const C2(10,10,10)
void ShowTime() const
{}
常对象不能背赋值只能初始化,只能访问常成员函数,常成员函数不允许修改常对象
静态常数据成员在类外说明和初始化,常数据成员类内初始化;
class Clock{}
const int Clock::b=3;
C++继承与派生
代码重用和软件重用和扩充
单继承多继承 多层继承多层派生
公有私有保护继承
exp:
class Clock{}
class AlarmClock: public Clock
基类:直接基类,间接基类,无循环
公有继承
私有继承:成员函数和对象可以访问public 和protected 的成员或对象,但在类外不能通过派生对象访问
exp:class Point{void ShowXY()}
class Circle :private Point
Circle C1;
C1.ShowXY()错误《可以重写同名函数覆盖然后把原函数封装进去》
//公有继承 对象访问 成员访问 public --> public Y Y protected --> protected N Y private --> private N N //保护继承 对象访问 成员访问 public --> protected N Y protected --> protected N Y private --> protected N N //私有继承 对象访问 成员访问 public --> private N Y protected --> private N Y private --> private N N
单继承的构造与析构
调用基类构造函数
调用内嵌成员对象的构造函数,调用顺序按照它们在类中定义的顺序
派生类自己的构造函数
构造 从上到下从基类到最外层
析构 从下往上
类型兼容
在公有派生的情况下,一个派生类对象可以作为基类的对象来使用的情况。
1.派生类的对象可以赋值给基类的对象
2.派生类对象可以初始化基类的引用
3.派生类对象的地址可以赋值给指向基类的指针
----实际上只访问从基类继承的成员,新增涉及到多态
多继承
同一个基类不允许两次继承
虚基类
解决数据不一致,二义性,节省内存。
虚基类的构造函数分:
没有定义构造函数
定义了默认的构造函数
定义了带参数的构造函数
构造函数为从虚基类开始,析构函数从最远派生类开始
公共虚基类子对象只初始化一次,中间看起来多次执行虚基类
在最远虚基类的构造函数定义对虚基类构造函数的初始化列表--不出错。
C++多态
1.
1.1静态联编
1.2动态联编
1.1//运算符重载---》实质是函数重载
一元运算符: @obj--compile to---> operator @ (obj)
二元运算符: obj1@obj2---compile to----@(obj1,obj2)
后置++ -- obj++---->operator++(obj,0)
前置与一元运算符一样
c++不允许以下五个重载其他都可以 . .* :: ?: sizeof
2.运算符重载
知识改造不是改变,功能相似
非成员,非友元,必须调用一些类中有公共接口提供的设置数据和读取数据的函数,且降低性能
重载为类的友元函数,vc要 using std::cout using std::endl;