C++类和对象基础知识

类和对象

在c语言中,程序是由若干的函数以及变量组成的,它们之间并没有很严格的关系,这就导致了当程序规模逐渐变大之后,就不易于程序的扩充以及维护。另外,当我们想要复用之前程序中的一些代码片段时,函数中的变量使得我们很难将其从程序中抽离出来。总之,结构化程序设计使得我们的程序难以扩充、难以维护、难以重用。

c++在c语言的基础上增加了面向对象程序设计(Object-oriented programming,OOP)的机制,而面向对象的这种机制恰好解决了c语言结构化设计的这种缺陷。简单来说,在面向对象程序设计中,我们可以依照以下的设计方法:

  1. 我们将某类客观事物的共同特点(属性)归纳出来,形成一个数据结构,可以用多个变量描述事物的属性。
  2. 将这类事物所能进行的行为也归纳出来,形成函数,这些函数就用来操作数据结构。
  3. 然后通过某种方式将这些数据结构与函数捆绑封装起来,从而形成一个类。

需要注意的是,被封装的函数只能访问与它封装在一起的数据结构,反之,这些数据结构也只能被与它封装在一起的函数所操作。这样就使得某一类事物的数据结构只能由与之封装的函数进行操作,而其它函数是无法访问其数据结构的。

案例
假设我们现在要实现一个矩形类,该如何表示呢?

  • 矩形有长(length)和宽(weight)两个属性

作为一个矩形,可以有哪些行为呢?

  • 设置长和宽
  • 计算面积
  • 计算周长

类的定义

我们将上面的矩形属性长(length)和宽(weight)以及与之对应的行为封装在一起,就能形成一个矩形类。

矩形属性成为“成员变量”,3个函数成为该类的“成员函数”,成员变量与成员函数统称为类的成员。

实际上,类看上去就像带函数的结构。

class Rectangle {
public:
	double length;//长
	double weight;//宽
    
	void init(double length_,double weight_) {//设置长和宽
		length = length_;//设置长
		weight = weight_;//设置宽
	}
	double Area(){//计算面积
		return length * weight;
	}
	double Perimeter() {//计算周长
		return 2 * (length + weight);
	}
};//分号不可省略

关键字 public 确定了类成员的访问属性。在类对象作用域内,公共成员在类的外部是可访问的。除了public,我们还可以指定成员为privateprotected,我们将在后续进行讲解。

这样我们就得到了一个矩形类。

  • lengthweight 分别为矩形的长和宽
  • initAreaPerimeter分别为类的成员函数,函数中的lengthweight 指的是成员变量的lengthweight

定义 C++ 对象

普通定义

我们有了Rectangle类之后就要去使用它,声明类的对象,就像声明基本数据类型的变量一样,如下代码所示:

int main() {
	Rectangle r;//声明一个对象
	double length = 10.0;
	double weight = 10.0;
	r.init(length, weight);//初始化对象
	cout << "矩形面积为:" << r.Area() << endl;
	cout << "矩形周长为:" << r.Perimeter() << endl;
	return 0;
}

我们声明了一个对象r,类型为Rectangle我们通过.运算符可以访问类的成员,通过r.init(length, weight);来初始化对象,此时调用了类的成员函数void init(double length_,double weight_),设置了矩形的长和宽。

接下来,通过r.Area()以及r.Perimeter()计算矩形的面积以及周长,并通过cout输出,运行上面的代码,我们可以得到如下结果:

矩形面积为:100
矩形周长为:40

通过指针定义

除了上面所展示的普通定义之外,我们还可以通过指针来定义类的对象,其用法与基本数据类型的指针定义相同。

int main() {
	double length;//长
	double weight;//宽
	Rectangle *r;//声明一个对象指针
	r = new Rectangle;//为对象动态分配内存空间
	r->init(length, weight);//初始化对象
	cout << "矩形面积为:" << r->Area() << endl;
	cout << "矩形周长为:" << r->Perimeter() << endl;
    delete r;//释放动态分配的空间
	return 0;
}

对象指针的创建与基本数据类型的指针定义相同,通过Rectangle *r;创建一个对象指针,并通过new运算符为其动态分配内存空间,值得注意的是,在访问对象的成员时,需要使用->运算符进行访问,而不再是.运算符。

执行上面代码,我们可以获得与普通定义相同的结果:

矩形面积为:100
矩形周长为:40

最后,在使用完之后,我们需要使用delete运算符来释放动态分配的空间。

通过类可以定义变量,类定义出来的变量,也成为类的实例,就是我们所说的对象

访问数据成员

类的对象的公共数据成员(public)可以使用直接成员访问运算符.->来访问。

使用.访问

int main() {
	Rectangle r;//声明一个对象
	double length = 10.0;
	double weight = 10.0;
	r.init(length, weight);//初始化对象
	cout << "矩形长为:" << r.length << endl;
	cout << "矩形宽为:" << r.weight << endl;
	return 0;
}
  • 通过r.init(length, weight);,我们调用了初始化函数初始化了矩形的长和宽。

  • 通过r.length,得到了矩形的长。

  • 通过r.weight,得到了矩形的宽。

执行上面的代码,得到如下结果:

矩形长为:10
矩形宽为:10

使用->访问

int main() {
	double length;//长
	double weight;//宽
	Rectangle *r;//声明一个对象指针
	r = new Rectangle;//为对象动态分配内存空间
	r->init(length, weight);//初始化对象
	cout << "矩形长为:" << r->length << endl;
	cout << "矩形宽为:" << r->weight << endl;
	delete r;//释放动态分配的空间
	return 0;
}

执行代码,得到下面结果:

矩形长为:10
矩形宽为:10

与使用.运算符的结果一致。

对象的内存分配

一般的,我们认为对象所占用的内存大小为,等于所有成员变量的大小之和

对于上面的Rectangle类,sizeof(Rectangle)=16

int main() {
	double length;//长
	double weight;//宽
	Rectangle r;//声明一个对象
	cout << "sizeof(Rectangle)=" << sizeof(Rectangle) << endl;
	return 0;
}

运行上面代码,得到如下结果:

sizeof(Rectangle)=16

注意

  • 并不是所有的类所占内存空间大小都为成员变量之和,有时还需要考虑对齐等情况,会有所差异。
  • 一个类的成员函数只有一份,为所有成员共享,故类的成员函数所占用内存空间没有计算。
  • 每个对象都有自己的存储空间,一个对象的值改变了并不会影响另一个变量

类的成员函数和类的定义分开写

当我们的类拥有很多的成员变量以及成员函数的时候,如果将所有的成员函数的实现都写在类的定义当中的话,就会显得十分的臃肿,不利于代码的阅读。此时,我们可以将类的定义以及实现分类来写,类的定义当中仅写成员函数的定义,而成员函数的实现则写到类的外面。

class Rectangle{
public:
	double length;//长
	double weight;//宽
	void init(double length_, double weight_);//设置长和宽
	double Area();//计算面积
	double Perimeter(); //计算周长
};//分号不可省略

我们改写上面所示的代码,在类的实现当中仅写成员函数的定义。将成员函数写在类外,如下代码所示:

void Rectangle::init(double length_, double weight_) {
	length = length_;
	weight = weight_;
}
double Rectangle::Area() {
	return length * weight;
}
double Rectangle::Perimeter() {
	return 2 * (length * weight);
}

其基本格式为:

返回值类型 类名::函数名(参数表){
    函数体
}

通过类名::说明后面的函数为类的成员函数,而非普通函数。

类成员的可访问范围

在类的定义中,用以下的关键字来说明类成员的访问范围:

  • private:私有成员,只能在成员函数内访问

  • public:公用成员,可以在任何地方访问

  • protected:保护成员,具体用法以后讨论

  • 以上三种关键字出现次数和先后顺序没有限制

  • 没有说明访问范围的默认为private

class Student {
	char name[10];//默认为private
public:
	char sex;
	void printInfo();
private:
	int age;
protected:
	time_t birthday;
};

例如在上面的学生类中,name属性没有指定访问范围,值默认缺省为private

对于上面的类,假设我们有如下外部调用:

int main() {
	Student stu;
	stu.printInfo();//OK
	stu.sex;//OK
	stu.name;//错误,不能访问私有成员
	stu.birthday;//错误,不能访问保护成员
}

我们仅能访问类的公有成员(public),不能访问其它属性的成员。

对于如下的内部调用:

void Student::printInfo() {
	cout << age << endl;//OK
	cout << birthday << endl;//OK
}

在类的成员函数内部,我们可以访问所有的成员。

注意

  • private属性的成员只能通过类的成员函数访问,不能在类外部访问。
  • 在类的成员函数内部,能够访问当前对象的全部属性、函数以及同类其它对象的全部属性、函数
  • 在类的成员函数以外的地方,就只能访问该类对象的公有成员(public)

设置私有成员的的机制叫“隐藏”,隐藏的目的时强制成员变量的访问一定要通过成员函数进行,使得成员变量不能被外部所访问到,确保了成员变量的安全,同时也易于以后的维护。

成员函数的重载与缺省

类的成员函数也可以进行重载以及缺省参数值,其用法与普通函数的重载与参数缺省相同。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值