友元类、组合类
友元关系
封装的目的是为了实现信息隐蔽,一个对象的私有成员只能通过自己的成员访问到,类外想要访问私有成员只能通过该类提供的公有成员间接地进行
但是上面这种方式通常是以函数调用的方式进行的,不方便并且开销大,因此,c++提供了友元的机制来打破私有化的界限,即一个类的友元可以访问该类的私有成员
友元函数
友元函数可以直接访问类对象的公有,私有成员
声明可以放在类的任何位置(哪一个段都没有区别),但是友元函数不属于类,不是该类的成员函数,因此一般的友元函数也没有this指针
调用时需要将对象作为参数传入友元函数内,调用方式和普通函数一样不需要通过对象,如:
Point类代表点(其中有点的坐标(x,y)的数据),需要一个函数计算任意两点间的距离
单从实现的角度来说并不复杂,首先只需要定义一个计算距离的函数,通过Point类的对象提供点的坐标,并在类外通过成员函数访问即可计算距离,或者也可以在类中定义一个成员函数,然后一个对象通过上面的方法接受另一个Point类对象提供的坐标,调用成员函数计算距离即可
但这两种法式显然不如友元快捷高效,并且计算距离应该是一个独立的功能,反映两点间的关系 ...
静态成员、常成员
静态成员
当用关键字static说明一个类成员时,该成员为静态成员,包括静态数据成员,静态成员函数
静态数据成员,如:
class ABCD{int value;static int s_value;};
对静态成员除了在类内声明外还必须在类声明体外进行定义和初始化(不应该在构造函数中初始化,并且大部分环境也不支持这样做)
int ABCD:😒_value=n;
注意初始化时还要指定数据类型。如果没有给定初始化值,那么默认初始化为0(此时分配在在bss段)。
同c中的静态数据类型相似,类中的静态成员在所有类对象中共享一个存储空间,如:
ABCD A,B,C,D;
其中A,B,C,D四个对象具有value和s_value两种数据成员,但value属性在每个对象中都有一份存储空间,而类的所有对象共享类的静态数据成员,无论建立多少个该类的对象,静态数据成员都只有一份拷贝,因此静态数据成员属于类,而不属于具体某个对象
具体来说,静态成员变量不占用对象的内存,静态成员变量和普通的静态变量类似,都在内存分区中的静态存储区分配内存
创建的时间也比较特殊,不是在声明类时分配,也不是 ...
对象指针、对象数组、对象引用
对象指针
与c语言类似,c++可以通过使用指向对象的指针变量来访问对象及对象的公共成员
定义和用法与结构体指针相似,也是数据类型加指针名的形式,如:
class Clock{public:void ShowTime();};
Clock clock,*p=&clock;p->ShowTime();
this指针
c++为每个非静态成员函数都提供了一个关键字this,代表一个指针,this指针是一个隐含的指针常量,指向被成员函数操作的那个对象,即当前类变量(对象)的首地址
this的值具有特殊的含义,总是指向当前调用对象,因此值不能修改,只能用在类的内部,通过this可以访问类的所有访问属性的成员,this虽然用在类的内部,但是只有在对象被创建以后才会给this指针赋值,并且这个赋值的过程是编译器自动完成的,不需要用户干预,用户也不能显式地给this指针赋值。
在构造函数中使用this指针会存在问题,应该尽量避免,因为通常this指针在对象构造完毕后才完全生成,而在构造函数执行过程中,对象还没有完全生成,所以this指针也是没有完全生成的
当成员函数的参数和成员变 ...
构造函数、析构函数
构造函数
自动解决数据成员的初始化问题
构造函数是类的一种特殊成员,本质上也是类的成员函数,函数名和类名相同,注意构造函数没有返回类型(因为没有变量来接收返回值),可以有参数也可以没有
不论声明还是定义,构造函数名前面都不能出现返回值类型,函数体中不能有return语句
当创建类的一个新对象时,构造函数被自动调用,完成对象的初始化工作,例:
class Clock
{
private:
int hour,minute,second;
public:
Clock(int h,int m,int s):hour(h),minute(m),second(s){};
};
int main(){
Clock clock(1,2,3);
return 0;
}
实现构造函数
声明构造函数后需要实现构造函数:初始化数据成员
有两种实现构造函数的方式
(在c++11的扩展以前,类的声明体内是不能初始化成员变量的,只有一个特例是static const int类型)
赋值语句的方式:
Clock(i ...
类和对象
面向对象技术
面向对象技术几大关键特征:
数据抽象,封装
类实现
继承
类派生,能更容易地定义与其他类相似却又不相同的新类,并编写忽略相似类型之间区别的程序
动态绑定
编译器在运行时决定使用基类中定义的函数还是派生类中定义的函数
抽象
抽象是对具体问题(对象)进行概括,提炼出这一类对象的公共性质并加以描述的过程
先注意问题的本质及描述,其次是实现过程或细节
数据抽象:描述某类事物(对象)共有的属性或状态
行为抽象:描述某类事物(对象)共有的行为特征或具有的功能
抽象是相对的,而非绝对的
研究问题时,如果侧重点不同,可能产生不同的抽象结果
解决同一问题时要求不同,也可能产生不同的抽象结果
开发一个人事管理软件,关心的是员工的姓名,性别,工龄,工资,工作部门等相关信息
如果开发学籍管理系统,那么关心的是学生的姓名,性别,年龄,籍贯,所在学院等相关信息
抽象定义了一个事物的本质,从软件设计的角度而言,使用类的封装机制来实现抽象
类
类也是一种自定义的构造数据类型
定义和使用类的基本过程
对事物进行抽象
根据抽象结果定义类的特性
实现类中成员函数的逻辑 ...
函数重载、默认形参
函数重载
函数重载本质上是一种多态性的简单体现(静态绑定)
c语言中对不同数据类型的数据进行功能相似的操作时必须编写很多个不同的函数
如:对两个整数,两个实数,一个整数一个实数,三个整数求和
->此时需要四个功能相似但名称不同的函数
而c++中可以让四个函数名称相同,即函数重载
对两个以上参数的函数具有相同的函数名,但形参个数或类型不同,编译器可以通过实参个数或者类型的最佳匹配自动决定调用哪个函数,例:
int add(int a,int b){return a+b;}
float add(float a,float b){return a+b;}
int add(int a,int b,int c){return a+b;}
float add(int a,float b){return a+b;}
int main{
int a,b,c;float x,y;
add(a,b); //调用int add(int a,int b)
...
常量、内联函数、引用
常量
常量是指在程序运行过程中,其值不能被改变的量
在程序中直接使用常量会出现可读性差,可维护性差的缺点。通常用符号常量解决常量的问题
c中定义符号常量的方法有两种,第一是宏定义,宏定义不能有赋值符,不能以分号结尾,不进行类型检查,只在编译时进行简单的替换,运行时不占内存空间;
第二是在c99标准中加入的const关键字的使用,但这里const定义的是一个只读的变量,并不是真正的常量(打印内存地址和普通变量、全局变量等对比一下就会发现c语言的const变量实际在栈上)
c++中对const进行了扩展,使其可以真正进行符号常量的定义,基本格式为:
const 数据类型 符号常量名=数值;
在声明时必须初始化(即使是全局变量),并且在程序中间不能改变其值(在类的声明中除外,const成员在声明时不需要初始化,但是在实例中必须初始化)
const定义的符号常量在程序运行期间占据内存空间,只是用const来指明该内存空间的只读约束
内联函数
函数涉及到形参空间的分配,实参到形参的数据拷贝,函数入口的转换等等,时间空间的开销相对较高
而宏定义在编译时进行简单的原样替换时开销非常低,并且 ...
命名空间
命名空间
一个中大型软件往往由多名程序员共同开发,会使用大量的变量和函数,不可避免地会出现变量或函数的命名冲突,当所有人的代码都测试通过,没有问题时,但将它们结合到一起就有可能会出现命名冲突
namespace关键字用来定义一个命名空间,语法格式为:
namespace 命名空间名{}
命名空间又称为名字空间,是表达多个变量和多个函数组合成一个组的方法,可以包含变量、函数、类、typedef、#define等,最后由花括号{}包围
主要为了解决名字冲突(用户自定义的类型名,函数名,变量名等)的问题
域解析操作符
::是域解析操作符,在c中用来指明要使用的命名空间
c标准库中的函数或者对象都是在命名空间std中定义的,所以使用标准函数库中的函数或对象都要使用std来限定
当然也可以引入命名空间(using namespace std),在之后语句省略std,不用的话如果定义同名变量则该命名空间的变量会被局部变量覆盖掉
c++输入输出示例程序:输入十个整数,对其进行冒泡排序后输出
#include<iostream>
using namespace std;
int ...
从c到c++
c是c的基础,只有充分掌握c并理解c和c的不同,才能理解和运用c++解决问题
c++数据类型
c中数据类型整体可以分为基本数据类型和构造数据类型
基本数据类型包括:整型,实数型,字符型,空值型
构造数据类型包括数组,结构,指针,枚举,联合
c++在c的基础上对数据类型进行了拓展,新增了基本数据类型中的逻辑类型,构造数据类型中的引用类型
以及新增了一个大类:类数据类型
基本数据类型
字符:char, unsigned char
整型(普通,长,短):int, unsigned, long, unsigned long, short, unsigned short
浮点(实数)型(单,双精度):float, unsigned float, double, unsigned double
逻辑类型:bool
c99借鉴c++加入了bool类型,但c程序中为避免编译环境标准不同等问题一般是将int重命名为bool(但int占用内存大于bool,后者只占1字节)
类型转换:各种类型高低顺序为(低类型->高类型,按占用内存空间大小,高类型转低类型可能丢失数据)
short/c ...
常见标准库函数
标准库提供了很多功能各异的函数
不同的头文件中声明了功能各不相同的库函数,不同的库函数的实现有时也需要借助其他的库函数
一般情况只供标准库中其他函数使用的名字以下划线开始,防止与用户程序中的名字冲突,所有标准库都遵循该约定
以下对其中一些特别有用的函数做一个简要概述,更多详细信息参见网上的文档
字符串操作函数
此类函数一般在头文件<string.h>中定义
下面的各个函数中,s与t是char*类型,c与n是int类型
注意s和t的返回,避免发生越界错误
strcat(s,t) 将t指向的字符串连接到s指向的字符串的末尾
strncat(s,t,n) 将t指向的字符串中前n个字符连接到s指向的字符串的末尾
strcpy(s,t) 将t指向的字符串复制到s指向的位置
strncpy(s,t,n) 将t指向的字符串中前n个字符复制到s指向的位置
strcmp(s,t) 根据s指向的字符串小于(s<t)、等于(s==t)或大于(s>t)t指向的字符串的不同情况,分别返回负整数、0或正整数
strncmp(s,t,n) 同strcmp相 ...