C与C++的区别
C语言是面向过程的,关注的是过程,分析出解决问题的步骤,然后通过函数调用逐步解决问题。
C++是面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互解决问题。
类与对象
类的定义
class name
{
int a;
int add(int a, int b)
{
return a + b;
}
};
class为定义类的关键字,name为类的名字,{}中为类的主体,a被称为类的属性或成员变量,add被称为类的方法或成员函数。
定义类时,有两种方式
- 类的声明和定义全部放在类体中
- 类的声明放在.h文件中,类的定义放在.cpp文件中
类的访问限定符及封装
C++实现封装的方式:用类将对象的属性和方法结合在一块,让对象更加完善,通过访问权限选择性地将其接口提供给外部的用户使用。
访问限定符有三种:public(公有)、protected(保护)、private(私有)
- public修饰的成员在类外可以直接被访问
- protected和private修饰的成员在类外不能直接被访问
- 访问限定符作用域是从该访问限定符到下一个访问限定符出现为止
- class的默认访问权限为private,struct为public
类的作用域
类定义了一个新的作用域,类的所有成员都在类的作用域中。在类外定义成员时,需要使用 :: 作用域解析符指明成员属于哪个类域。
class A
{
public:
void Print();
private:
int a;
};
void A::Print()
{
cout << a << endl;
}
类的实例化
用类类型创建对象的过程,称为类的实例化
- 类只是一个模型,限定了类的成员,定义出一个类并没有分配实际存在的空间
- 一个类可以实例化出多个对象,这些对象占用实际的物理空间,存储类成员变量
类对象存储
一个类的大小,实际上就是类中成员变量之和,但要注意内存对齐。空类的大小为一个字节,原因是编译器给了空类一个字节来唯一标识这个类。
this指针
this指针是一个隐藏的指针参数,指向当前对象。
- this指针的类型:类类型* const
- 只能在“成员函数”的内部使用
- this指针本质上是一个成员函数的形参,是对象调用成员函数时,将对象地址作为实参传递给this形参,所以对象中不存储this指针
- this指针是成员函数第一个隐含的指针形参
类的默认成员函数
类的6个默认成员函数
一个类中什么成员都没有,叫做空类,空类并不是什么都没有。任何一个类在我们不写的情况下,都会自动生成6个默认成员函数
class A
{
public:
A()//无参构造函数
{}
A(int a, int b, int c)//带参构造函数
{
_x = a;
_y = b;
_z = c;
}
~A()//析构函数
{
free(_arr);
}
A(const A& s)//拷贝构造函数
{
_x = s._x;
_y = s._y;
_z = s._z;
}
private:
int _x;
int _y;
int _z;
int* _arr;//需要用深拷贝解决
};
void test()
{
A s1;//调用无参构造函数
A s2(1,2,3);//调用带参构造函数
//如果通过无参构造函数创建对象,对象后面不用跟括号,否则就成了函数声明
}
构造函数
构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,保证每个数据成员都有一个合适的初始值,并且在对象的生命周期内只调用一次。其特征如下:
- 函数名与类名相同
- 无返回值
- 对象实例化时编译器自动调用对应的构造函数
- 构造函数可以重载
- 如果类中没有显式定义构造函数,则编译器会自动生成一个无参的默认构造函数,一旦用户显式定义编译器将不再生成
- 无参的构造函数和全缺省的构造函数以及编译器默认生成的构造函数都称为默认构造函数,并且默认构造函数只能有一个
析构函数
析构函数是特殊的成员函数。其特征如下:
- 析构函数的函数名是在类名前加上字符~
- 无参数无返回值
- 一个类有且只有一个析构函数,若未显式定义,则系统自动生成默认的析构函数
- 对象生命周期结束时,编译系统自动调用析构函数
拷贝构造函数
拷贝构造函数是特殊的成员函数。只有单个形参,该形参是对本类类型对象的引用(一般用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用。其特征如下:
- 拷贝构造函数是构造函数的一个重载形式
- 拷贝构造函数的参数只有一个且必须要使用引用传参,使用传值方式对引发无穷递归调用
- 若未显式定义,则系统生成默认的拷贝构造函数。默认的拷贝构造函数对象按内存存储字节序完成拷贝,这种拷贝叫做浅拷贝或值拷贝。
赋值运算符重载
运算符重载是具有特殊函数名的函数。
函数名为:关键字operator后面接需要重载的运算符符号。
函数原型:返回值类型 operator操作符(参数列表)
注意:
- 不能通过连接其他符号来创建新的操作符
- 重载操作符必须有一个类类型或者枚举类型的操作数
- 用于内置类型的操作符,其含义不能改变
- 作为类成员的重载函数时,形参看起来比操作数少一个,是因为操作数有一个默认的形参this,限定为第一个形参
- *、::、sizeof、? :、.这5个运算符不能重载
赋值运算符重载
class A
{
public:
A& operator=(const A& s)
{
if(this != &s)
{
_x = s._x;
_y = s._y;
_z = s._z;
}
}
private:
int _x;
int _y;
int _z;
};
- 参数类型为隐藏的this指针和const修饰的类类型引用
- 返回值类型为类类型引用
- 检测是否自己给自己赋值
- 返回*this
- 若没有显式定义,编译器自动生成一个。
const成员
将const修饰的类成员函数称之为const成员函数,const修饰类成员函数,实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改。
- const对象不可以调用非const成员函数
- 非const对象可以调用const成员函数
- const成员函数内不可以调用其它的非const成员函数
- 非const成员函数内可以调用其它的const成员函数
取地址及const取地址操作符重载
这两个默认成员函数一般不用重新定义,编译器默认会生成
class A
{
public:
A* operator&()
{
return this;
}
const A* operator&()const
{
return this;
}
private:
int _x;
int _y;
int _z;
};