布尔类型
赋值:两种方式
a. 直接赋值:true/false
b. 数字赋值:非零为真 (会溢出,不可以在存储时使用,可以在判断时使用)
内联函数
含义:
将内联函数中的代码块复制到调用处,用空间换取时间,即内存膨胀
减少了出入栈的时间,增大了程序代码段的容量
声明方式:
inline type function();
注意使用时机:
相应函数的代码块内容太多时不建议使用
相应函数的内容中有循环时不建议使用
内容简短.调用频繁时使用
函数的重载
含义:
编译器通过参数列表的不同来区分不同的函数,即函数的唯一性依赖于参数列表
参数列表的不同是指:对应位置上的参数类型不同
注意:函数重载不可以考虑返回值
用法:
同名不同参:
int func(int x);
float func(int x);//不可重载!
/****************************/
int f(float x);
float f(int x);//可以重载
特殊情况:
调用重载的函数时如果传入参数和各个重载的参数列表==都相同或者都不相同==时会报错
函数参数缺省
含义:为函数参数中的某一个或几个参数设定默认值,提高了代码的可重用性
用法:
type function(type1 para1=default1,...);
//e.g.
int fun(int x=1,float val=5.14)//传参顺序从左-右,缺省值必须从后往前!!
{
printf("%d,%f\n",x,val);
return 0;
}
注意事项:
设定的默认值必须是个常量,不可以是变量
默认值只需要在声明时给出
函数的传参顺序从左-右,有缺省值的参数必须从后往前排列
避免出现二义性,例如:
int fun(int x=1,float val=5.14);
int fun();
int main()
{
fun(1,1.1);
fun(); //无法确定/区分重载类型!
return 0;
}
引用
含义:
给变量/对象其一个别名
用法:
int n=0;
int& a=n;//小名在前,真名在后
注意事项:
定义引用时必须初始化
小名在前,真名在后
命名空间
含义:
为命名划分集合,有些变量/对象名字会重名,在使用时指定集合即可
用法:
namespace NAME
namespace NAME1
{
int number;
int func(); //局部函数
}
可以嵌套定义
namespace NAME1
{
namespace NAME1_1
{
int number=114;
}
}
可以起别名
namespace n=NAME1;//起别名,命名空间过长时使用
访问方式:作用域符号::加变量/对象/成员名字
NAME1::number
注意事项:
不能在函数内定义命名空间
重复定义命名空间时(命名污染)会自动合并
在重复定义之前,重复定义的命名空间的内容不会被合并(代码的顺序执行)
不同命名空间的成员具有不同的内存/含义
字符串类
含义:字符串类,比普通的字符串高级,具有自己的函数
用法:
==额外==包含头文件#include <string>
直接赋值:
string str;
str="hello";
取长度的函数:str.length()
直接判断相等:(bool)str1==str2
取指定位置上的字符:char ch=str.at(INDEX)
注意事项:using std::string;
类
三种权限:
public: 共有的,类内外均可访问
private: 私有的,只有类内可以访问
protected:保护的,其子类可以访问
用法:
成员权限关键字可以重复,有效区域至下一个权限关键字出现为止
成员函数可以先声明,然后在外部实现
注意事项
成员函数在类内定义则是内联函数
必须实例化之后再用
定义之后要加分号
构造函数
含义:
是成员函数
负责对象的初始化
特点:
创建对象时会自动调用
函数名和类名相同
没有返回值类型
参数表不作要求
可以重载(比如拷贝构造函数)
用法:
无参构造:
class NAME
{
public:
NAME();
};
NAME::NAME()
{
}
带参构造:用成员初始化列表
class NAME
{
public:
int data1;
int data2;
NAME();
};
NAME::NAME():data1(114),data2(514)
{
}
注意事项:
不定义构造函数则默认有一个构造函数 (缺省)
类外定义对象必须是共有的
如果定义的构造函数都是带参数的,则由系统缺省的无参构造函数会自动失效
必须带参实例化对象
最先构造的对象最后析构
拷贝构造函数
含义:
构造函数的重载,从一个对象得到另一个完全相同的对象
调用时机: (重点)
用一个对象给另一个对象初始化
任意一个函数的参数、返回值是类的对象时调用拷贝构造
过程:
实参的值拷贝给形参;
返回值有接受体时:函数栈区在运行结束时会被释放,则返回一个拷贝
没有接受体时:直接析构
总结:
a. 类的对象需要拷贝时调用\
b. 涉及到 某一类的对象在不同内存区块(堆/栈)之间转移时会自动调用(系统默认给,可以自定义)
用法:
定义:classname(classname& object,...)
注意:
拷贝时要注意对象里的指针,拷贝后的指针和被拷贝对象的指针会指向同一块内存!
应该重新申请内存,并指向;
其第一个参数必须是属于本类的对象的引用
析构函数
含义:
对象生命周期结束时自动调用
负责内存清理等工作
用法:
声明: ~classname();
注意事项:
没有返回值类型
没有参数
必须是共有的 public
一个类有且仅有一个析构函数
this指针
含义:
在类的成员函数中使用, 用来表示“当前对象”.
成员函数只有一份,不会实例化到各个对象,谁调用,指向谁
对象在调用函数时想要访问属于自己的成员时,就需要告诉函数是谁在调用它,以便找到对象所有的成员
性质:
其类型属于当前的类,不属于某一个对象
类内函数访问类内成员时,this指针总是指向调用者对象
用法:
和类的指针用法相同
class ClassName
{
public:
int data;
void setData(int data)
{
this->data=data;
}
};
静态(static)成员
分类: static变量和函数
类内的静态变量
性质:
共享: 所有同类对象共享同一个静态数据的内存, 不属于任意对象,属于类的,可以用作用符号访问
生存周期: 比所在的类长
注意事项:
初始化必须在类外
在类外初始化时无需加static
class ClassName
{
public:
static int data=10;//ERROR:带有类内初始值设定项的成员必须为常量
}
/*************/
int ClassName::data=10;//正确的
类内的静态函数
性质/和普通成员函数的区别:
函数的实现不能依赖于普通成员,可以依赖静态成员
可以在没有对象时调用(见上条)
没有this指针(见上条)
不能访问普通成员函数(见上条)
用法:
class ClassName
{
public:
static int data;
int number;
static void function()
{
data=10; //正确的
this->data=10; //错误的
number=114; //错误的
}
}
应用: 单例模式——只允许该类最多存在一个对象
原理:
每个类里面有一个原装出场的钥匙
钥匙是私有的,保密且安全
实例化对象时会把对象分配到这个钥匙, 即钥匙被修改
当且仅当钥匙是原装出厂的才能实例化对象
实现:
class singleInstance
{
public:
static singleInstance* getInstance();
private:
static singleInstance* p; //熔断器
};
singleInstance* singleInstance:: p=NULL;
singleInstance* singleInstance::getInstance()//核心实现
{
if(p==NULL)
p=new (singleInstance);
return p;
}
总结
相比于其他成员, 类内的静态成员有以下特点
静态性:功能类似于专属于类的保安, 其存在不会受对象的实例化和析构影响
共享性:静态成员可以在不同的对象内占用同一块内存空间
单向封闭性:静态成员之间只能互相通信,而普通成员可以访问类内的所有变量
常量成员
分类:
常量对象
常量变量成员
常量函数
常量变量
特点:
不可被修改
用法:
定义:
class ClassName
{
public:
const int data;
}
初始化const变量:初始化列表
ClassName::ClassName() data(114514)
{
}
注意事项:
const变量不可以在类内初始化
常量对象
特点:
对象的所有普通成员(除去static成员)都不可以被修改
用法:
定义:
const ClassName Object;
特殊情况:
可以修改static成员
不能访问/调用普通(非static)成员
class ClassName
{
public:
static int s_data;
const int c_data;
}
常量成员函数
特点:
不可以修改所在对象的普通(非static)成员,但是可以访问
用法:
定义:
class ClassName
{
public:
typename function() const;
};
注意事项:
可以修改static成员
class ClassName
{
public:
static int data1;
typename function() const;
};
typename ClassName::function() const
{
data1=113;//const函数可以修改静态成员
}
总结
const的性质是:
恒定性: 不可修改/通信于属于自己所在类的成员
封闭性: const成员只能和类外(static)成员进行相互通信
和static成员的对比
const保护了自己内部成员,而static让成员不受类的“拘束”/独立于类存在
友元关系
含义:
使两个类/对象/函数之间可以通信, ==但未必是相互的==
若b是a的友元,则a中的公私成员均对b开放
用法:
定义:
友元类: 令b是a的友元,则: 即: “友去主家”,“友被主访”
class a
{
public:
friend class b;
};
class b{};
- 友元函数
- 全局函数/成员函数都可以
typename globalFunction();
class a
{
public:
friend b::typename classFunction();
friend globalFunction();
};
class b
{
public:
typename classFunction();
};
注意事项:
友元的包含不区分公私
单向的
没有传递性
继承和派生
含义:
在已有的一个或多个类的基础上创建新的类
是类和类之间的关系
新建的类称为子类/派生类,已有的类成为基类/父类
分类:
单继承: 子类只有一个父类
多继承: 子类有N个父类
继承权限:
分类:
public
private
protected
父类内的访问权限和子类的继承权限的关系
继承是在继承父类内的全部成员,继承权限是相当于使用权
父类访问\子类继承 | public | private | protected |
public | public | public | public |
private | 不可访问 | 不可访问 | 不可访问 |
protected | protected | private | protected |
a.父类共有成员在继承后的访问权限和继承方式相同
b.私有成员继承后不可访问
c.保护成员在继承之后一定是被保护的,只有两种状态:相对保护和绝对保护(private)
用法:
定义:权限+父类
class father
{
public: int data1;
private: int data2;
protected: int data3;
};
class son: public father
{
public:int data;
private:int num;
public:void fun();
};
注意事项:
即使父类的访问权限是私有的private, 也会被继承到子类里,只不过是不可访问的而已
父类和子类的关系
- 子类不会继承构造和析构函数
- 子类可以添加新对象
- 在子类中访问父类的成员要用作用域符号
关于赋值:
father f;
son s;
father* pf;
son* ps;
f=s; //大的可以给小的赋值,但会丢失部分信息
s=f; //小的不可以给大的赋值,因为小的不全(C++里对未定义的/未初始化的行为零容忍)
pf=&s;
ps=&f; //指大不指小,因为指小的会越界访问
总之,不可以读写没定义的东西
联编和多态
联编:
动态联编
静态联编
动态联编实现的条件:
有类,且内部有虚函数成员,动态联编的行为必须定义在虚函数
要有继承关系
多态:
来源: 子类继承而来的函数相比原来有新的改动,又不希望新定义一个函数, 想把原来的替换掉
当类和类之间有继承等层次结构时,同一函数在类族内的不同层次会体现不同形态(重新实现)
虚函数:
定义:
class ClassName1
{
public:
virtual typename function();
};
class ClassName2: public ClassName1
{
public:
typename function();
};
特点:
定义后会生成虚函数表,用于储存所有虚函数所对应的指针
类族内的同名函数在继承时会替换(重新定义)
虚函数表不会被继承()
存在指向虚函数表的指针:虚指针(四字节)
先声明的在虚函数表前面
访问虚函数:通过虚指针访问虚函数表找到虚函数的地址
虚析构:
来源:
释放内存时系统会根据类型调析构,此时不会释放子类中的部分内存,会剩余内存碎片、内存泄漏, 比如:
father* pf=new son;
delete pf;
whk@whk-PC:./a.out
构造了一个父类
构造了一个子类
结构了一个子类
解构了一个父类
含义:
把父类的析构函数定义成虚函数,释放内存时会调用子类析构
运算符重载
含义
给予运算符一个新的含义
分类:
类内
类外(全局重载)
二者的作用范围不相同
用法: 以加号/复数运算为例
类内:
class complex
{
public:
complex(double im = 0.0, double re = 0.0);
~complex();
void outputComplex() const;
const complex &operator+(complex &obj) const
{
return complex(this->re + obj.re, this->im + obj.im);
}
private:
double im;
double re;
};
类外
const complex operator+();