C++随笔——“类与对象”查漏补缺

参考视频:C++语言程序设计基础——清华大学郑莉老师

参考教材:C++语言程序设计教程(第3版)清华大学出版社

1、private、public、protected为访问权限,用来控制对类的成员的存取,默认访问权限为private
默认访问权限,也叫作缺省访问权限,如:

class b {
	int a;
};

这样写是私有的,相当于编译系统加上了private这个关键词。
2、在C++中,class的成员默认是private权限,struct默认是public权限。按照习惯,struct中只包含数据成员不包含成员函数
3、类只是一种类型,类中的数据成员不占内存空间,因此在定义数据成员时不能给数据成员赋初值
4、放在类中定义的成员函数为内联函数。(内联函数: 一种用空间换时间的方案,在编译时将函数体代码插入到函数调用处,将调用函数的方式改为顺序执行方式。应该定义在前,使用在后

inline 函数类型 函数名(形参表)
{
	函数体;
}

5、在类外定义成员函数的格式如下:

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

6、在数据成员中不能定义该类类型的变量,但是在成员函数中可以使用该类定义变量(对象)。
7、类与对象的关系: 数据类型与变量的关系
8、private成员不能直接在类外存取,可以通过调用public中的成员函数,来间接存取private成员。
9、对象的初始化和清理工作分别由构造函数析构函数完成。
10、对象消失时的清理工作并不是由析构函数完成,而是靠用户在析构函数中添加清理语句完成。
11、类中的对象消失的顺序与建立的顺序相反。
12、函数形参和返回值都是类中的对象时,则在调用函数时,会为形参建立一个临时形参对象,且调用复制构造函数;在返回前会建立一个临时返回对象用来存储返回值,在执行return语句时将返回值复制给临时返回对象,且调用复制构造函数在函数调用结束后,临时形参对象消失,析构函数被调用,临时返回对象也消失,析构函数被调用。
13、在调用函数时,如果用一个类的常量初始化实参,而不是用一个已经存在的对象初始化实参,则不会调用复制构造函数,只会调用构造函数。
14、复制构造函数和对象赋值的区别: 复制构造函数是用一个存在的对象去构造另一个不存在的对象;对象赋值是两个对象都已经存在,用一个对象的值去覆盖另一个对象的值,不会调用复制构造函数
15、浅层复制: 直接将原对象的数据成员值依次复制给新对象中对应的数据成员,并不会为新对象另外分配内存资源。如果原对象的数据成员是指针,两个指针对象实际上指向的是同一块内存空间,在这种情况下,进行析构时,按照对象建立的顺序,先析构新对象,释放内存,再对原对象进行析构,由于同一块内存不会释放两次,所以在析构时会出现错误,带来数据安全方面的隐患。
在这里插入图片描述
深层复制: 如果类的数据成员中有指针类型,必须定义一个特定的复制构造函数,不仅可以实现原对象和新对象之间的数据成员的复制,还可以为新对象分配单独的内存资源
在这里插入图片描述
16、对象指针:类似于int类型指针、float类型指针,可以用类来定义对象指针,通过指针来访问对象成员。
17、如同通过对象名访问对象的成员一样,对象指针只能访问类的公有数据成员和函数成员,采用 “->”运算符 访问公有数据成员和函数成员。

#include "pch.h"
#include<iostream>
using namespace std;

class Clock {
private:
	int H, M, S;
public:
	void SetTime(int h, int m, int s) {
		H = h;
		M = m;
		S = s;
	}
	void ShowTime() {
		cout << H << ":" << M << ":" << S << endl;
	}
	Clock(int h = 0, int m = 0, int s = 0) {
		H = h;
		M = m;
		S = s;
	}
	Clock(Clock & p) {
		H = p.H;
		M = p.M;
		S = p.S;
	}
	void TimeAdd(Clock *cp);
	void TimeAdd(int h, int m, int s);
	void TimeAdd(int s);
};

void Clock::TimeAdd(Clock *cp)
{
	H = (cp->H + H + (cp->M + M + (cp->S + S) / 60) / 60) % 24;
	M = (cp->M + M + (cp->S + S) / 60) % 60;
	S = (cp->S + S) % 60;
}

void Clock::TimeAdd(int h, int m, int s)
{
	H = (H + h + (M + m + (S + s) / 60) / 60) % 24;
	M = (M + m + (S + s) / 60) % 60;
	S = (S + s) % 60;
}

void Clock::TimeAdd(int s) {
	H = (H + (M + (S + s) / 60) / 60) % 24;
	M = (M + (S + s) / 60) % 60;
	S = (S + s) % 60;
}

int main()
{
	Clock c1;
	Clock c2(8, 20, 20);
	c1.TimeAdd(4000);
	c1.ShowTime();
	c2.TimeAdd(&c1);
	c2.ShowTime();
	c2.TimeAdd(2, 0, 0);
	c2.ShowTime();
	return 0;
}

在这里插入图片描述
18、对象引用: 就是对某类对象定义一个引用,其实质是通过将被引用对象的地址赋给引用对象,使二者指向同一个内存空间,这样引用对象就成为了被引用对象的 “别名”
19、除非是作为函数参数与函数返回值,对象引用在定义时必须要初始化。
20、对象引用不占用内存空间。
21、对象引用通常用作函数参数,不仅具有对象指针的优点,而且更简单方便。如:上面代码中

void Clock::TimeAdd(Clock *cp)
{
	H = (cp->H + H + (cp->M + M + (cp->S + S) / 60) / 60) % 24;
	M = (cp->M + M + (cp->S + S) / 60) % 60;
	S = (cp->S + S) % 60;
}

c2.TimeAdd(&c1);

可以替换为

void Clock::TimeAdd(Clock & cp)
{
	H = (cp.H + H + (cp.M + M + (cp.S + S) / 60) / 60) % 24;
	M = (cp.M + M + (cp.S + S) / 60) % 60;
	S = (cp.S + S) % 60;
}

c2.TimeAdd(c1);

22、对象数组:以对象为元素的数组。定义、赋值、引用与普通数组一样。
注意:不带初始化列表的对象数组,其初始化靠调用不带参数的构造函数(默认构造函数)完成。

#include "pch.h"
#include<iostream>
#include<string>
using namespace std;

class Score {
private:
	int number;
	char * name;
	double score;
	double final_score;
	double total;
public:
	//Score(int = 0, char = NULL, double =0, double = 0, double = 0){}		//默认构造函数
	Score(){}		//默认构造函数
	Score(int number, char * name, double score, double final_score, double total = 0)
    {
		this->number = number;
		this->name = name;
		this->score = score;
		this->final_score = final_score;
		this->total = total;
	}
	void count()
	{
		total = score * 0.6 + final_score * 0.4 + 0.5;
	}
	void show()
	{
		cout << number << "\t" << name << "\t" << score << "\t" << final_score << "\t" << total << endl;
	}
};

int main()
{
	Score a[3];        //需要调用默认构造函数
	Score b[3] = { Score(200607001,"liuna",80,79),
				   Score(200607002,"cuipeng",90,85),
				   Score(200607003,"zhoujin",70,55) };
	for (int i = 0; i < 3; i++)
	{
		b[i].count();
	}
	for (int i = 0; i < 3; i++)
	{
		b[i].show();
	}
	return 0;
}

在这里插入图片描述
23、动态对象:指随时动态建立并可随时消失的对象。格式如下:

对象指针 = new 类名(初值表);

24、建立动态对象时要调用构造函数。
25、在堆中建立的动态对象不能自动消失,需要使用delete语句 (可以写在析构函数中) 删除对象。格式如下:

delete 对象指针;

26、建立一个动态对象数组格式如下:

对象指针 = new 类名[数组大小];

删除一个动态对象数组的格式如下:

delete[] 对象指针;
    Score *a;
	a = new Score[3];
	a[0].SetScore(200607001, "LiuNa", 80, 79);
	a[1].SetScore(200607002, "CuiPeng", 90, 85);
	a[2].SetScore(200607003, "ZhouJun", 70, 55);
	
    delete[] a;

27、在建立动态对象数组时,要调用构造函数,调用次数与数组大小相同;在删除对象数组时,要调用析构函数,调用次数与数组大小相同。
28、this指针: 一个特殊指针,指向当前对象,表示当前对象的地址。例如,当形参与类中的数据成员写成一样时,可以使用this指针加以区分,否则运行结果错误

void SetScore(int number, string name, float score, float final_score, float total = 0) {
		this->number = number;
		this->name = name;
		this->score = score;
		this->final_score = final_score;
		this->total = total;
	}

29、组合类:一个类中含有其他类的对象。贴上教材中的代码:

#include "pch.h"
#include<iostream>
#include<string>
using namespace std;

class Clock {
private:
	int H, M, S;
public:
	Clock(int H = 0, int M = 0, int S = 0)
	{
		this->H = H;
		this->M = M;
		this->S = S;
	}
	void SetTime(int H = 0, int M = 0, int S = 0)
	{
		this->H = H;
		this->M = M;
		this->S = S;
	}
	void ShowTime()
	{
		cout << H << ":" << M << ":" << S << endl;
	}
	int GetH()
	{
		return H;
	}
	int GetM()
	{
		return M;
	}
	int GetS()
	{
		return S;
	}
};
class TrainTrip {
private:
	string TrainInfo;
	Clock EndTime;
	Clock StartTime;
public:
	TrainTrip(string TrainInfo, Clock S, Clock E)
	{
		this->TrainInfo = TrainInfo;
		StartTime = S;
		EndTime = E;
	}
	Clock TripTime()
	{
		int h, m, s;
		int carry = 0;
		Clock tTime;
		(s = EndTime.GetS() - StartTime.GetS()) > 0 ? carry = 0 : s += 60, carry = 1;
		(m = EndTime.GetM() - StartTime.GetM() - carry) > 0 ? carry = 0 : m += 60, carry = 1;
		(h = EndTime.GetH() - StartTime.GetH() - carry) > 0 ? carry = 0 : h += 24;
		tTime.SetTime(h, m, s);
		return tTime;
	}
};

int main()
{
	Clock c1(20, 04, 10), c2(04, 12, 2);
	Clock c3;
	TrainTrip t1("k16", c1, c2);
	c3 = t1.TripTime();
	c3.ShowTime();
	return 0;
}

在这里插入图片描述
30、类中的成员以其在类中声明的先后顺序依次构造,而不是根据构造函数的初始化列表中的成员对象构造函数声明的先后顺序来决定。
在上面代码中,EndTime定义在前,StartTime定义在后,所以尽管构造函数如下
TrainTrip(string TrainInfo, Clock S, Clock E)
仍然是先对E调用构造函数。
31、静态数据成员: 一种类属性,描述类的所有对象的共同特征的一个数据项,从而实现了同类的不同对象之间的数据共享。类内声明,格式如下:

static 数据类型 静态数据成员名;

类外初始化,格式如下:

数据类型  类名::静态数据成员名 = 初始值;

32、静态成员函数: 属于整个类,可以用来存取类的静态数据成员。可以通过类名和对象两种方式调用静态数据成员。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值