吉林大学陈伟-面向对象程序设计(基于C++语言讲解)

表达式:
能作为左值表达式的,一定存在真实的物理空间。
lambda表达式。
指针:
1.空指针:NULL/nullptr
2.type* varName,以*号为界,右边是变量,左边是指向的东西
3.解引用
4.指针运算:int *p,p+n<<=>>偏移size(int)*n个单位,取数组元素a[k]就是*(a+k)
5.可以不初始化
数组:
1.int[5] a;
2.指针数组:int *array[5];
3.数组指针:int (*p)[5];//int[5] *p
引用:
1.是一个别名
2.对应的变量,对象必须存在
3.必须初始化
4.void(int& a,int& b);
#define 宏
1.无类型检查
2可用于条件编译
#define debug
int main(){
int a=100;
#ifdef debug
cout<<a<<endl;
do1();
#else
do2();
#endif
}
}
3.特殊应用:
cout<<_LINE_<<endl;当前语句所在行数
cout<<_FILE_<<endl;当前语句所在文件名
cout<<_FUNCTION_<<endl;当前语句所在函数
命名常量:
1.格式:const int CAED_COUNT=54;
2.命名常量可以放在头文件里,不会重复定义,进行常量折叠(直接替换)
const和指针:
1.const int *pt=&a与int const *pt=&a等价,pt可以指向任何东西,但指向的东西不可以通过pt修改,别的指针可以改
2int *p=pt;//报错
3.T * const pt= &a;必须初始化;指针指向不能该,可以通过指针改变指向的内容;

4.char * str="hello world";等价于const char * str="hello world";
const和引用
1.int b=100;
const int& aa=b;//不可以通过修改b
const int& bb=1;//正确,但前面必须加const
2.const引用主要用于函数参数传递
函数声明:
1.:

成员函数有可能加const
2:

函数调用的过程:
1.记录调用现场
2.在栈中建立局部变量
3.恢复调用现场
4.谁来负责清栈;
调用者负责:可处理变参和固定参数函数
被调用者负责:只能处理固定参数函数
调用约定:

常见windows所有的API函数都是标准调用(_stdcall)
_thiscall调用是所有面向对象语言的成员函数所采用的调用约定,隐藏一个默认参数this指针
函数重载:
多个同名函数,但它们具有不同参数类型,参数顺序,参数个数,const修饰,异常说明数时,可以同时存在,称为函数重载。
int Func();
int Func(int);
int Func(int,int);
int Func(int,int)const;
int Func(int)throw();
int Func(int)throw(int,MyE,YourE);
int Func(MyClass obj);

名字重整:由编译器在函数名字的基本信息之上,添加必要的参数信息,形成新的函数名字,用于区分不同的重载函数
例:void Fun(int)经重整后,生成类似_Fun_int的新函数名
缺点:一个程序中难以确定另一个程序中经重整的函数名
禁止函数重载:
extern "C"{//以下函数按c语言形式处理,不允许名字重载
int Fun();
int Func(int);
int OtherFun();
}
extern "C" void MyFunc(int);
函数的参数列表:
1.缺省参数:应该在函数原型中提供,若无函数原型,才在定义中给出,一般只提供一次
2.定义中的参数,可以无名(一般用于函数重载)


函数的返回:
1.按值返回:
默认返回int;void;内置类型(基本类型,派生类型);返回普通内置类型基本都是const;自定义类型(类,结构);
2.返回指针:T*f();等价于T* const f();
但不等价于const T* f();
3.返回引用:

int & max(int& a,int& b){return a>b?a:b;}
int a=5,b=7;
max(a,b)=4;//把两者较大的改为4
类型的抽象表示:
ADT:与具体表示无关
与现实世界无关
任意性和无穷性
a ADT:
name{
数据:
关系:
操作:
}
操作是区分类型的关键
类型的表示及定义:

类的定义可采用前置声明(避免循环定义,降低文件依赖性)
类的成员:
1数据成员:

struct和class用引用也可以
2成员函数:
类和对象:
classname objectname;
classname *pobj=new classname;

向对象obj发送消息f,f的参数是20。
向对象o2发送消息f,f的参数是99。
通过指针向对象obj发送消息f,f的参数是5。
对象的存储:

判断两个对象是不是同一个对象是通过判断地址是否一致完成的
对齐方式:按一个字节对齐,按两个字节对齐,按四个字节对齐,在编译时设定。
静态数据成员存储在程序区。
成员函数的实现:


this指针是非静态成员函数隐含的第一个参数,用来指明被实例化的当前对象。
this指针:


对于Ultraman& Ultraman::fight(Monster& m);函数,考虑以下几种变体:
1.若返回值为void,则无法连续击打小怪兽
2若返回值不加&,输出的happiness是不一样的,但不是同一个Ultraman击打的
外联实现和内联实现:
外联实现:

类里写函数声明,类外写实现。
内联实现:

1.类里直接给实现(默认前面有个inline)
2.类外加inline关键字
3.建议编译器在调用处直接展开函数代码

使用内联函数的不足:
可能会产生类之间的依赖性
解决方式:
1前置声明
2外联实现


访问控制:
pubblic:任何类都可以访问,类外可以访问
private:本类(不是本对象)或友元可以访问

封装与信息隐蔽:

封装与信息隐蔽的作用:

常成员函数:


即使func 3()大括号的内容为空,也会报错。因为func3()有能力修改对象的成员变量。
不带const函数隐含的的第一格变量为T* const this.

定义函数本意时未打算修改,则应该加const.
实例变量实例方法类变量类方法:


1.常成员函数可以修改类变量,因为类变量不属于当前对象,它存储在程序区(不是this指针所指)。
2.类变量必须显式初始化。typename classname:: var= ;
3.类方法只能访问类变量类方法,不能访问实例变量和实例方法。

8.1自定义构造函数

在没有explicit的情况下,发f(100)会根据100,Name(int)进行隐式调用,即会把100直接转化为Name(100)的对象,但是在由explicit的情况下,只允许显式调用,f(100)会直接报错。

私有自定义构造函数允许类内函数进行调用
两者都只允许实例化一个对象,但是指针的形式更常用。

缺省的构造函数
无参数的,public的
只有在用户没有提供自定义构造函数的情况下,才由编译器提供

右边三种认为提供了自定义构造函数
对象的初始化

1.程序执行到构造函数大括弧时,对象已经创建,大括弧里只是对数据成员赋值。所以,在大括弧内对const数据成员赋值就会出错。
2.赋值初始化只是对象初始化的一种形式
3.

4.初始化列表:
class A{
public:
A(int a){
_a = a;//有参构造,没有默认构造函数
}
private:
int _a;
};
class Student{
public:
Student(int a, int age)
:_aa(a)
,_age(age)
,_no(001)
{}//必须在初始化列表中进行初始化
private:
A _aa;//自定义类型,且没有自己的默认构造函数
int& _age;//引用
const int _no//const的成员变量
};
析构函数:

1构造函数和析构函数都有this指针
2构造函数和析构函数都不能加const
3右边的例子析构函数可给可不给
4在Card析构时,由于desc是对象,所以调用desc的析构函数
构造和析构函数的访问:


delete pa时,调用pa的析构函数~A(),大括弧执行完毕后,执行b1,b2的析构函数。
对象的拷贝:

红色部分都要进行拷贝复制


注意对象拷贝构造和赋值的区别
拷贝构造时从无到有创建一个对象,在该语句前,该对象是不存在的
如上图右侧,a1=a2即为赋值,B b2(b1);B b3=b1;都是拷贝构造;
缺省拷贝构造函数:

浅拷贝是按bit位拷贝
浅拷贝:

浅拷贝只对对象内的数据成员进行拷贝。由于静态数据成员是属于类的,不属于对象,所以不在浅拷贝的考虑范围之内