类的引入
定义:
C++ 在 C 语言的基础上增加了面向对象编程,C++ 支持面向对象程序设计。类是 C++ 的核心特性,通常被称为用户定义的类型。类用于指定对象的形式,是一种用户自定义的数据类型,它是一种封装了数据和函数的组合。类中的数据称为成员变量,函数称为成员函数。类可以被看作是一种模板,可以用来创建具有相同属性和行为的多个对象。
可以看出,既然被称为自定义类型,就和C语言中结构体类似,但是C++引入了类的概念,且兼容C,所有struct在C++中也做了升级。
C语言结构体中只能定义变量,在C++中,结构体内不仅可以定义变量,也可以定义函数。比如:
之前在数据结构中,用C语言方式实现的栈,结构体中只能定义变量;现在以C++方式实现,会发现struct中也可以定义函数。
struct Stack
{
void Init(int capacity = 4)
{
a = (int*)malloc(sizeof(int) * capacity);
if (nullptr == a)
{
perror("malloc申请空间失败");
return;
}
_capacity = capacity;
_size = 0;
}
int* a;
int _capacity;
int _size;
};
上面结构体的定义,在C++中更喜欢用class来代替。
但是结构体和类的最大的区别就是:结构体内的变量和函数默认是 public 的,可以在结构体作用域之外的地方使用;但是类的变量和函数默认是 private 的,只能被类作用域内的函数使用;即结构体默认不加访问限定符默认公有访问,但是类默认的是私有访问,出了类域就无法对其访问。
类的定义
定义一个类需要使用关键字 class
,然后指定类的名称,并类的主体是包含在一对花括号中,主体包含类的成员变量和成员函数。
定义一个类,本质上是定义一个数据类型的蓝图,它定义了类的对象包括了什么,以及可以在这个对象上执行哪些操作。
class className
{
// 类体:由成员函数和成员变量组成
};
// 一定要注意后面的分号
成员变量的定义方式:
像上面写的栈的代码,成员函数的参数名和成员变量的名称可能相同,所以,对类中的成员变量进行一定规则的命名,便可以很好的区分
class Date
{
void Init(int year)
{
_year = year;
}
int _year;
};
// 或者
class Date
{
void Init(int year)
{
mYear = year;
}
int mYear;
};
成员函数的定义方式:
1.声明和定义全部放在类体中,需注意:成员函数如果在类中定义,编译器可能会将其当成内
联函数处理。
即:
class Date
{
void Init(int year)
{
mYear = year;
}
int mYear;
};
- 类声明放在.h文件中,成员函数定义放在.cpp文件中,即声明与定义分离,在类里面声明,在其他地方定义。注意:成员函数名前需要加 类名::
即
class Point
{
int x, y;
public:
int getX();
};
int main()
{
Point point;
point.getX();
return 0;
}
int Point::getX()
{
x = 1000;
cout << x << endl;
return x;
}
注意: 第二种方式定义的时候要加类和域的限定符,这样编译器才知道这是哪个域的成员函数,同时如果要给缺省参数的话要在声明的时候给。类中的函数也支持重载。
一般情况下,更期望采用第二种方式。
类的访问限定符及封装
访问限定符
C++实现封装的方式:用类将对象的属性与方法结合在一块,让对象更加完善,通过访问权限选择性的将其接口提供给外部的用户使用。
class 类名{
private:
私有变量和函数
public:
公有变量和函数
protected:
保护变量和函数
};
- public修饰的成员在类外可以直接被访问
- protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的)
- 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
- 如果后面没有访问限定符,作用域就到 } 即类结束。
- class的默认访问权限为private,struct为public(因为struct要兼容C)
注意:访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别
封装
面向对象的三大特性:封装、继承、多态。
面向对象的语言都具有的特性。
在类和对象阶段,主要是研究类的封装特性,那什么是封装呢?
封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。
封装本质上是一种管理,让用户更方便使用类。 比如:对于电脑这样一个复杂的设备,提供给用户的就只有开关机键、通过键盘输入,显示器,USB插孔等,让用户和计算机进行交互,完成日常事务。但实际上电脑真正工作的却是CPU、显卡、内存等一些硬件元件。
在C++语言中实现封装,可以通过类将数据以及操作数据的方法进行有机结合,通过访问权限来隐藏对象内部实现细节,控制哪些方法可以在类外部直接被使用。
即可以将类的成员变量封装为私有,而成员函数封装为公有,只允许使用成员函数来对成员变量进行访问,而不允许私自访问成员变量。
类的实例化
在最开始也有写道,
定义一个类,本质上是定义一个数据类型的蓝图,它定义了类的对象包括了什么,以及可以在这个对象上执行哪些操作。
用类的类型创建对象的过程,称为类的实例化
类提供了对象的蓝图,所以基本上,对象是根据类来创建的。声明类的对象,就像声明基本类型的变量一样。
Person是一个蓝图,一个说明,而man是一个对象。
Person类是没有空间的,只有Person类实例化出的对象才占有空间。
如何计算类的大小
class A
{
public:
void PrintA()
{
cout << _a << endl;
}
private:
char _a;
};
类中既可以有成员变量,又可以有成员函数,那么一个类的对象中包含了什么?如何计算
一个类的大小?
通过以下代码测试:
class A
{
public:
void PrintA()
{
cout << _a << endl;
}
private:
char _a;
};
// 类中既有成员变量,又有成员函数
class A1 {
public:
void f1() {}
private:
int _a;
};
// 类中仅有成员函数
class A2 {
public:
void f2() {}
};
// 类中什么都没有---空类
class A3
{};
int main()
{
cout << sizeof(A) << endl;
cout << sizeof(A1) << endl;
cout << sizeof(A2) << endl;
cout << sizeof(A3) << endl;
return 0;
}
结论:
一个类的大小,实际就是该类中“成员变量”之和,成员函数不占用空间,当然要注意内存对齐
注意空类的大小,空类比较特殊,编译器给了空类一个字节来唯一标识这个类的对象。相当于用一个字节来对这个类进行一个占位,说明这个类存在过。
成员函数的存储就在公共代码段里面,当然编译器肯定有自己的规则去标识是哪个类的成员函数。