类定义、可访问性与成员函数
class A
{
public:/*……*/
protected:/*……*/
private:/*……*/
};//不要遗漏分号!
public:类中类外均可见
private:类中可见,类外不可见,在第一段中默认为private
protected:类和派生类中可见
建立类对象时开辟存储空间,内存大小包括数据成员但不包括函数
成员函数在类中声明,通常类外定义,类内定义作内联函数处理
函数首部: 返回类型 类名::函数名(参数表)
构造函数与析构函数
形式:
构造函数: 类名::类名(参数表);
析构函数: ~类名::类名(参数表);
Attention:
1、函数名与类名相同
2、对象建立和销毁时自动调用,但用new动态创建的对象必须delete,否则会内存泄漏
3、构造函数无返回类型,析构函数无参数与返回类型
4、可以但不应该定义在私有部分
5、先创建的对象最后析构,采用栈的规则,先进后出
6、构造函数不能为常成员函数、静态成员函数、友元函数、虚函数;
重载构造函数
Attention:
注意匹配二义性,X()和X(int i=0)在不传参的情况下会产生匹配二义性,即系统无法根据参数表确定调用哪个函数
补充示例:以下代码也会产生匹配二义性
#include <iostream>
using namespace std;
class A
{
public:
int x;
A(int ,float) { cout << 1; }
A(int, double) { cout << 2; }
};
int main()
{
ios::sync_with_stdio(false); cin.tie(0), cout.tie(0);
A(1, 2);
return 0;
}
拷贝构造函数
用途:防止生成的新对象与原有的对象共用存储空间,即实现深复制
写法:
类名::类名(const 类名&引用名);
口诀:常类引用
调用拷贝构造函数的时机:
1、用已有对象创建新对象
2、传递类类型参数(传值)
3、返回类类型
浅复制与深复制:对于指针数据成员,浅复制抄地址,深复制抄内容
Attention:系统为类重载了=运算符,所以在执行赋值操作时会间接地执行拷贝构造函数
默认重载的=定义:
constexpr A &A::operator=(const A &)
在类对象传参及返回类对象时,系统都会自动执行默认的复制构造函数,系统默认拷贝构造函数为浅复制
e.x.
//A为类名
A g()
{
A aa3;
return aa3;//先将aa3拷贝构造匿名对象obj,再删除aa3,obj在aa3之后删除.
}
常成员
常数据成员:不可在构造函数内初始化,需用参数初始式赋值
初始化示例:
e.x.
//设Mclass为类名,M为常成员
//方法一:由构造函数用常量初始化
Mclass():M(5){}//相当于M=5,但是我们不能把“M=5;”这句话放进函数体
//方法二:用函数参数初始化
Mclass(int num):M(num){}
常对象:说明语句以const为前缀,全部数据成员只读
e.x. const A a;//A为类名
常成员函数:函数首部以const后缀,不得修改this所指对象的数据成员,但是可以修改其他变量以及其他对象
e.x.
class X
{
int g() const;
}
静态成员
静态数据成员:存储性质上是全局变量,作用域是类。
必须在类内声明,类外定义。
不可在类内及main函数中赋初值,可在类外赋初值。
定义若不赋值,则自动赋值为0.
所有对象均共享同一静态成员
定义方式: e.x. int Mclass::m = 0;
静态成员函数:无this指针,只能访问静态数据成员
在类外可用 “类名::”与对象两种形式调用
常对象只能调用常成员函数或静态成员函数
友元
友元函数:
作用:协同访问多个类的私有成员
友元函数在类内声明,表明可访问该类的数据成员,其可访问性和对类成员的访问性不受在类中声明位置(private、protected、public)影响
声明方式:friend 函数首部;
友元函数不是类的成员函数,因此定义、调用同普通函数相同,但在参数表中需显式指明调用对象
//e.x.
//类中声明,A为类名
friend void friendFun(A*,int);
//类外定义
void friendFun(A* p,int m){/*……*/}
友元类:获得调用其他类成员的权限
声明方式:
class A
{
friend class B;
}
类的包含
先执行成员类的构造函数,再调用自身构造函数,析构顺序相反(栈的规则)
参数初始式:对普通数据成员相当于赋值,对类数据成员相当于调用构造函数
说明方式:构造函数名(变元表):数据成员(变元表)……