以下为个人学习笔记和习题整理
课程:计算机程序设计(C++)- 西安交通大学 @ 中国大学 MOOC
https://www.icourse163.org/course/XJTU-46006

# 课堂笔记

# 构造函数

在声明一个对象后,紧接着要给对象初始化,对象初始化实质上就是对所有数据成员赋值。

如果对象中某个数据成员未赋值,则该数据成员的值不确定,那么该对象的值不完整。

构造函数 Constructor 用于创建一个对象,提供了初始化该对象的一种简便手段。

语法格式
<类名> (<参数表>)
{
	<函数体>
}

注意:

  • 构造函数的函数名必须与类名相同
  • 构造函数没有返回值
  • 其功能是将对象中的所有数据成员进行初始化,一般由一系列赋值语句构成
  • 由系统在声明对象时自动调用

# 有无构造函数的区别

在前面章节中的程序声明变量

int a=0; 
int a(0);
struct Date today={2013,3,19};
struct Date today(2013,3,19);

以上为变量声明的同时赋初值,即都允许初始化。

  • 对于无构造函数的类,声明变量(对象)不允许初始化
CLOCK alarm={10,53,11}; // 错误
CLOCK alarm(10,53,11); // 错误
  • 有构造函数就允许初始化
Date birthday(1998,12,12); // 正确
Date birthday={1998,12,12}; // 错误

# 重载构造函数

  • 一个类中允许定义多个构造函数
  • 在声明对象时自动选择执行某个构造函数

数据成员初始化的四种方法:

  1. 在构造函数的函数体中进行初始化
Date(Date &d)
{
	year=d.year;
	month=d.month;
	day=d.day;
}
  1. 在构造函数的头部初始化
<类名>::<构造函数名>(<参数表>):<变量1>(<初值1>),<变量n>(<初值n>){}
Date::Date():year(1900),month(1),day(1)
{
}
  1. 混合初始化:前两种方式结合
Date::Date(int y,int m,int d):year(y),month(m)
{
	day=d;
}
  1. 使用默认参数初始化
Date(char yy[], int mm = 1, int dd = 1)
{
	year = atoi(yy);
	month = mm;
	day = dd;
}

# 例子:日期类中 4 个重载构造函数

#include<iostream>
#include<string.h>
#include<stdlib.h>
using namespace std;
class Date
{
	int year,month,day;
	public:
		// 无参构造函数
		Date():year(1900),month(1),day(1) { }
		// 默认参数构造函数
		Date(int yy,int mm = 1,int dd = 1);
		// 日期对象参数构造函数
		Date(Date &d):year(d.year),month(d.month),day(d.day){};
		// 字符串日期构造函数
		Date(char *ps);
		void print_ymd();
};
// 默认参数构造函数的定义
Date::Date(int yy,int mm,int dd):year(1900),month(1),day(1)
{
	if (yy>=1900&&yy<=9999)
	{
		year = yy;
	}
	else
	{
		return;
	}
	if (mm>=1&&mm<=12)
	{
		month = mm;
	}
	else
	{
		year=1900;
		return;
	}
	if (dd>=1&&dd<=31)
	{
		day = dd;
	}
	else
	{
		year=1900;
		month=1;
		return;
	}
};
// 重载构造函数的定义
Date::Date(char *ps):year(1900),month(1),day(1)
{
	char py[5],pm[3],pd[3];
	strncpy(py,ps,4);
	ps=ps+5;
	strncpy(pm,ps,2);
	ps=ps+3;
	strncpy(pd,ps,2);
	int yy=atoi(py),mm=atoi(pm),dd=atoi(pd);
	if (yy>=1900&&yy<=9999)
	{
		year = yy;
	}
	else
	{
		return;
	}
	if (mm>=1&&mm<=12)
	{
		month = mm;
	}
	else
	{
		year=1900;
		return;
	}
	if (dd>=1&&dd<=31)
	{
		day = dd;
	}
	else
	{
		year=1900;
		month=1;
		return;
	}
}
// 测试
int main() {
	Date date1; // 使用无参构造函数
	cout << "date1:";
	date1.print_ymd();
	Date date2(2006); // 使用哪个构造函数?
	cout << "date2:";
	date2.print_ymd();
	Date date3(2006,4); // 使用哪个构造函数?
	cout << "date3:";
	date3.print_ymd();
	Date date4(2006,4,8); // 使用哪个构造函数?
	cout << "date4:";
	date4.print_ymd();
	Date date5(2006,14,8); // 使用哪个构造函数?
	cout << "date5:";
	date5.print_ymd();
	Date date6(date4); // 使用哪个构造函数?
	cout << "date6:";
	date6.print_ymd();
	Date date7("2008-08-08"); // 使用哪个构造函数?
	cout << "date7:";
	date7.print_ymd();
	return 0;
}

# 析构函数

  • 构造函数 Constructor :在对象创建时执行,提供了初始化对象的一种简便手段。
  • 析构函数 Destructor :在对象被撤销时 (前) 执行,用于完成对象被撤销前的一些清理工作。

具体地说,析构函数往往用于释放 “资源”,如在构造函数中动态申请的内存空间。
也可以被用来执行 “用户希望在最后一次使用对象之后所执行的任何操作”,例如输出有关信息等。

# 对象的存储空间

若一个类声明了五个对象,存储空间如何分配?

每个对象中的数据成员分配了存储空间。
所有对象中的函数成员共用一个存储空间,在代码区存放。

# 定义方法

<类名>::~<类名>()
{
	<函数体>
}

注意:

  • 函数名是类名前面加 ~ 符号
  • 析构函数不得返回任何值
  • 析构函数不得带有任何参数
  • 其主要功能是在撤销对象之前进行一些善后处理工作
  • 由系统自动调用

例子:日期类中增加析构函数

#include<iostream>
using namespace std;
class Date
{
	int year,month,day;
	public:
		// 无参构造函数
		Date():year(1900),month(1),day(1) { }
		// 默认参数构造函数
		Date(int yy,int mm = 1,int dd = 1);
		// 日期对象参数构造函数
		Date(Date &d):year(d.year),month(d.month),day(d.day){};
		// 字符串日期构造函数
		Date(char *ps);
		void print_ymd();
		~Date() { }; // 析构函数定义
		// 由于析构函数是空函数 (函数体中没有一条语句),没有感觉到析构函数被自动运行
};

# 实际意义的析构函数

机器人的特征
	姓名
	型号
	整数:待翻译的整数
	翻译的英文句子字符串:字符指针,句子有长有短
	……
机器人的功能
	翻译整数函数:形成英文字符串,并将字符串指针返回
	构造函数
	设置函数
	输出英文句子函数
	析构函数
机器人类
class robot
{
	private:
		// 机器人姓名
		char name[20];
		// 机器人型号
		char type[20];
	public:
		// 构造函数
		robot()
		{
			strcpy(name,"XXXXXX");
			strcpy(type,"XXXXXX");
		}
		// 设置修改数据
		void set(charn[],chart[])
		{
			strcpy(name,n);
			strcpy(type,t);
		}
		// 英文中每三位数读法相同,所以定义 out 函数翻译小于 1000 的整数
		void out(inta);
		// 将 1 至 1999999999 的整数翻译成英文句子
		void tran_int(intn);
		// 析构函数
		~robot(){};
};
// 定义两个全局字符指针数组,存取所需的单词
//num1 中为 1 到 19,空出了 0,所以可以直接用 num1 [n] 调用,得到 n 对应单词
static char *num1[]=
	{
		"","one ","two ","three ","four ","five ","six ","seven ","eight ",
		"nine ","ten ","eleven ","twelve ", "thirteen ","fourteen ",
		"fifteen ","sixteen ","seventeen ","eighteen ","nineteen "
	};
//num10 中为 20-90,空出了 0 和 1,所以可以直接用 num10 [n/10] 调用,得到 n 对应单词
static char *num10[]=
	{
		"","","twenty ","thirty ","forty ","fifty ","sixty ","seventy ",
		"eighty ","ninety "
	};
// 小于 1000 整数翻译函数
void robot::out(int a)
{
	int b=a%100;
	// 若百位不为零,输出百位数加 hundred,
	// 若此时十位个位均为 0,不加 and
	if(a/100!=0)
	{
		cout<<num1[a/100]<<"hundred ";
		if(b!=0)
		{
			cout<<"and ";
		}
	}
	// 当后两位在 20 以内时,直接调用 num1 [n],输出
	if(b<20) {
		cout<<num1[b];
	}
	// 当后两位大于 20 时
	else
	{
		// 先调用 num10,输出十位数
		cout<<num10[b/10];
		// 个位不为 0 时应输出 "-" 个位数
		if(b%10!=0)
		{
			cout<<"\b-"<<num1[b%10];
		}
	}
}
// 整数翻译函数
void robot::tran_int(int n)
{
	if(n>1999999999)
	{
		cout<<"dev C++平台无法处理大于1999999999位的数!"<<endl;
	}
	else
	{
		// 三位三位取出,存入 abcd 中
		int a=n/1000000000,
			b=(n%1000000000)/1000000,
			c=(n%1000000)/1000,
			d=n%1000;
		/// 当 abcd 不等于 0 时,输出并加上 billion, million 或 thousand
		if(a!=0)
		{
			out(a);
			cout<<"billion ";
		}
		if(b!=0)
		{
			out(b);
			cout<<"million ";
		}
		if(c!=0)
		{
			out(c);
			cout<<"thousand ";
		}
		if(d!=0)
		{
			// 据英文语法规则,最后两位前一定有 and
			if(d<100&&(a!=0||b!=0||c!=0)) {
				cout<<"and ";
			}
			out(d);
		}
		cout<<endl;
	}
}
int main() {
	int n;
	cout<<"请输入n:";
	cin>>n;
	cout<<n<<endl;
	robot brown;
	brown.tran_int(n);
	return 0;
}
改良机器人类
class robot
{
	private:
		// 机器人姓名
		char name[20];
		// 机器人型号
		char type[20];
		// 待翻译的整数
		int num; 
		// 指向英文字符串
		char *ps; 
	public:
		// 构造函数
		robot()
		{
			strcpy(name,"XXXXXX");
			strcpy(type,"XXXXXX");
			num=0;
			ps=new char[5];
			strcpy(ps,"zero");
		}
		// 设置修改数据
		void set(charn[],chart[])
		{
			strcpy(name,n);
			strcpy(type,t);
		}
		// 英文中每三位数读法相同,所以定义 out 函数翻译小于 1000 的整数
		char *out(int a);
		// 将 1 至 1999999999 的整数翻译成英文句子
		char *tran_int(int n);
		// 输出整数及其英文句子
		void print_num();
		// 析构函数
		~robot(){
			// 释放构造函数和 set 函数中动态申请的空间
			delete [] ps;// [] 表示 ps 指向的字符数组,整个数组都要被释放
		};
};
// 定义两个全局字符指针数组,存取所需的单词
//num1 中为 1 到 19,空出了 0,所以可以直接用 num1 [n] 调用,得到 n 对应单词
static char *num1[]=
	{
		"","one ","two ","three ","four ","five ","six ","seven ","eight ",
		"nine ","ten ","eleven ","twelve ", "thirteen ","fourteen ",
		"fifteen ","sixteen ","seventeen ","eighteen ","nineteen "
	};
//num10 中为 20-90,空出了 0 和 1,所以可以直接用 num10 [n/10] 调用,得到 n 对应单词
static char *num10[]=
	{
		"","","twenty ","thirty ","forty ","fifty ","sixty ","seventy ",
		"eighty ","ninety "
	};
// 类外定义小于 1000 整数翻译函数
char *robot::out(int a)
{
	// 定义字符数组 k,长度设为 1000,用空字符串初始化,用来存储英文字符串
	char k[1000]=""; 
	int b=a%100;
	// 若百位不为零,输出百位数加 hundred,
	// 若此时十位个位均为 0,不加 and
	if(a/100!=0)
	{
		// 不直接输出字符串,而是加入字符数组 k 中
		strcat(k,num1[a/100]);
		strcat(k,"hundred ");
		if(b!=0) {
			strcat(k,"and ");
		}
	}
	// 当后两位在 20 以内时,直接调用 num1 [n],输出
	if(b<20) {
		strcat(k,num1[b]);
	}
	// 当后两位大于 20 时
	else
	{
		// 先调用 num10,输出十位数
		strcat(k,num10[b/10]);
		// 个位不为 0 时应输出 "-" 个位数
		if(b%10!=0)
		{
			strcat(k,"\b-");
			strcat(k,num1[b%10]);
		}
	}
	// 动态申请一个存储空间
	char *p=new char[strlen(k)+1];
	// 大小则根据 k 中实际字符串的长度 + 1
	// 调用完毕需要释放该空间
	strcpy(p,k);
	return p;
}
// 类外定义整数翻译函数
char *robot::tran_int(int n)
{
	char *p; // 定义字符指针 p
	char kk[1000]=""; // 定义字符数组 kk,用来存放被翻译出的英文字符串,初始化成空字符串
	if(n>1999999999)
	{
		strcpy(kk,"dev C++平台无法处理太大的数!\n"); 
	}
	else
	{
		// 三位三位取出,存入 abcd 中
		int a=n/1000000000,
			b=(n%1000000000)/1000000,
			c=(n%1000000)/1000,
			d=n%1000;
		/// 当 abcd 不等于 0 时,输出并加上 billion, million 或 thousand
		if(a!=0)
		{
			p=out(a);
			strcpy(kk,p);
			strcat(kk,"billion ");
			delete [] p; // 释放在 out 函数中动态申请的空间
		}
		if(b!=0)
		{
			p=out(b);
			strcat(kk,p);
			strcat(kk,"million ");
			delete [] p; // 释放在 out 函数中动态申请的空间
		}
		if(c!=0)
		{
			p=out(c);
			strcat(kk,p);
			strcat(kk,"thousand ");
			delete [] p; // 释放在 out 函数中动态申请的空间
		}
		if(d!=0)
		{
			// 据英文语法规则,最后两位前一定有 and
			if(d<100&&(a!=0||b!=0||c!=0)) {
				strcat(kk,"and ");
			}
			p=out(d);
			strcat(kk,p);
			delete [] p; // 释放在 out 函数中动态申请的空间
		}
		p=new char[strlen(kk)+1];
		strcpy(p,kk);
		return p;
	}
}
// 类外定义设置函数
void robot::set(char n[],char t[],int m) // 设置修改数据
{
	strcpy(name,n);
	strcpy(type,t);
	if(num==m) {
		// 待翻译的整数没有变
		return;
	}
	else
	{
		num=m;
		delete [] ps; // 删除已有的英文句子
	}
	if(num>0) {
		char *tp=tran_int(num);
		ps=new char[strlen(tp)+1];
		strcpy(ps,tp);
		delete [] tp; // 释放在 trans_int 中动态申请的空间
	}
	else if(num==0)
	{
		ps=new char[5];
		strcpy(ps,"zero");
	}
	else
	{
		ps=new char[13];
		strcpy(ps, "负数不能翻译");
	}
}
int main() {
	robot brown;
	brown.print_num();
	int n;
	cout<<"请输入n:";
	cin>>n;
	brown.set("brown","800#",n);
	brown.print_num();
	return 0;
}
  • 存储空间的实际分配
    当运行 int n;robot brown; 后,
    存储空间分配如下:
Error: Failed to launch the browser process! spawn /Applications/Google Chrome.app/Contents/MacOS/Google Chrome ENOENT


TROUBLESHOOTING: https://github.com/puppeteer/puppeteer/blob/main/docs/troubleshooting.md
  • new 运算符操作结果
    当运行 brown.set(“brown”, “800#”,n); 后,
    堆区有字符串空间被占用,具体空间分配如下:
Error: Failed to launch the browser process! spawn /Applications/Google Chrome.app/Contents/MacOS/Google Chrome ENOENT


TROUBLESHOOTING: https://github.com/puppeteer/puppeteer/blob/main/docs/troubleshooting.md
  • 空析构函数的实际作用
    当析构函数为空函数时: ~robot() { }
    运行 return 语句后, 空间1 释放,而 空间2 保留

  • 析构函数的实际作用
    当析构函数为: ~robot() { delete [] ps; }
    运行 return 语句后, 空间1 空间2 均释放

# 对象与指针

Person类的设计
class Person
{
	private:
		char Name[9];
		char Sex;
		int Age;
		char Pid[19];
		char *Addr;
	public:
		Person()
		{
			strcpy(Name,"xxxxxxxx");
			Age = 0;
			Sex = 'x';
			strcpy(Pid,"xxxxxxxxxxxxxxxxxx");
			Addr=NULL;
		}
		Person(char *N, int A, char S,char *P,char *Ad)
		{
			strcpy(Name,N);
			Age = A;
			Sex = S;
			strcpy(Pid,P);
			int L=strlen(Ad);
			Addr=new char[L+1];
			strcpy(Addr,Ad);
		}
		~Person()
		{
			cout<<"Now destroying Person"<<Name<<endl;
			delete [] Addr;
		}
		void Register( char *name, int age, char sex,char *pid,char *addr);
		void ShowMe();
};
void Person::Register(char *name,int age,char sex,char *pid,char *addr)
{
	strcpy(Name,name);
	Age = age;
	Sex = sex;
	strcpy(Pid,pid);
	if(Addr!=NULL) {
		delete [] Addr;
	}
	int L=strlen(addr);
	Addr=new char[L+1];
	strcpy(Addr,addr);
}
void Person::ShowMe()
{
	cout<<Name<<" "<<Age<<" "<<Sex<<" "<<Pid<<" ";
	if(Addr!=NULL) {
		cout<<Addr;
	}
	cout<<endl;
}
int main()
{
	Person person1;
	Person person2("张三",19,'m',"610103199409192839","中国西安市咸宁西路29号");
	Person person3;
	cout<<"person1: ";
	person1.ShowMe();
	cout<<"person2: ";
	person2.ShowMe();
	person3.Register("李四",29,'w',"610103198409192493","中国上海市华山北路1845号");
	cout<<"person3: ";
	person3.ShowMe();
	person2.Register("赵五",29,'w',"610103198409152127","中国新疆乌鲁木齐市王家沟12号");
	cout<<"person2: ";
	person2.ShowMe();
	return 0;
}

# 指向对象的指针

定义方式
<类名> *<指针变量名表>;
例子
Person person1("Zhang3",19,'f');
Person *ptr=&person1;
ptr->ShowMe();

# 动态存储

定义方式
<对象指针>new <类名>(<名字初始化值>);
delete <名字指针>;
例子
Person *p=new Person;
delete p;
日期类修改
#include<iostream>
using namespace std;
class Date
{
	public:
		int year,month,day;
		void init(int y,int m,int k);
		void print_ymd();
};
void Date::init(int yy,int mm,int dd)
{
	month = mm;
	year = yy;
	day = dd;
}
void Date::print_ymd()
{
	cout<<year<<"-"<<month<<"-"<<day<<endl;
}
int main()
{
	Date date1;
	Date *p1 = &date1;
	p1->init(2006,5,13);
	p1->print_ymd();
	int *p2 = &date1.year;
	cout << *p2 <<endl;
	void (Date::*p3)(int ,int ,int); // 普通函数指针定义不行
	void (Date::*p4)();
	p3 = Date::init;
	p4 = Date::print_ymd;
	(date1.*p3)(2006,4,8);
	(date1.*p4)();
	return 0;
}
Person类修改
#include<iostream>
#include<string.h>
using namespace std;
class Person
{
	private:
		char Name[9];
		char Sex;
		int Age;
	public:
	Person()
	{
		strcpy(Name,"XXX");
		Age = 0;
		Sex = ' ';
	}
	~Person()
	{
		cout<<"Now destroying Person"<<endl;
	}
	void Register( char *name, int age, char sex);
	void ShowMe();
};
void Person::Register(char *name,int age,char sex)
{
	strcpy(Name,name);
	Age = age;
	Sex = sex;
}
void Person::ShowMe()
{
	cout<<Name<<'\t'<<Age<<'\t'<<Sex<<endl;
}
int main()
{
	Person *p1,*p2; // 声明两个指向对象的指针
	p1=new Person; // 动态生成一个 Person 对象
	cout << "person1: \t";
	p1->ShowMe();
	p1->Register("Zhang3", 19, 'm');
	cout << "person1: \t";
	p1->ShowMe();
	p2=new Person; // 动态生成一个 Person 对象
	cout << "person2: \t";
	p2->ShowMe();
	*p2 = *p1; // 对象之间的赋值
	cout << "person2: \t";
	p2->ShowMe();
	delete p1; // 释放 p1 指针指向对象所占的空间
	delete p2; // 释放 p2 指针指向对象所占的空间
	return 0;
}

# this 指针

  • 每一个类的成员函数都包含一个指向本类对象的指针,指针名为 this

  • 该指针指向本类对象的起始地址
    this 是指针, *this 就是对象(本对象)

  • 访问成员
    this->成员
    (*this).成员
    . 运算符优先级比较高,故需要使用 ()

#include <iostream>
using namespace std;
class Test
{
	int x;
	public:
		Test( int = 0 );
		void print();
};
// 构造函数
Test::Test(int a)
{
	x = a;
}
void Test::print()
{
	cout << " x = " << x <<endl;
	cout << "this->x = " << this->x << endl;
	cout << "(*this).x = " << ( *this ).x << endl;
}
int main()
{
	Test testObject( 12 );
	testObject.print();
	return 0;
}// 如果在 print () 函数中增加 int x=13; 输出结果如何变化?
  • 常用场合
  1. 当类中数据成员名与成员函数中的形参名相同时,用 this 指针加以区分
class Time
{
	private:
		int hour,minute,second;
	public:
		void set(int hour,int minute,int second)
		{
			this->hour = hour;
			this->minute = minute;
			this->second = second;
		}
}
// 两个整数为参数的构造函数
Fraction::Fraction(int a,int b)
{
	set(a,b); // 调用成员函数
}
// 设置分子、分母
void Fraction::set(int a,int b)
{
	this->a=a;
	this->b=b;
}
// 分数相加,本类对象加 u
Fraction Fraction::add(Fraction u)
{
	int tmp;
	Fraction v;
	v.a=a*u.b+b*u.a; // 分子
	v.b=b*u.b;// 分母
	tmp=divisor(v.a ,v.b);// 计算分子、分母的公约数
	v.a=v.a/tmp;// 约去公约数
	v.b=v.b/tmp;// 约去公约数
	return v; // 返回结果
}
  1. 成员函数需要返回指针或本对象时
// 分数相加,本类对象加 u
Fraction Fraction::add(Fraction u)
{
	int tmp;
	// Fraction v;
	a=a*u.b+b*u.a; // 分子
	b=b*u.b;// 分母
	tmp=divisor(a ,b);// 计算分子、分母的公约数
	a=a/tmp;// 约去公约数
	b=b/tmp;// 约去公约数
	return *this; // 返回结果
}

# 课堂讨论

  1. 如何通过指针访问对象数组的元素的成员。
    PERSON   Beijing[100];
    PERSON     *p=Beijing;
    如何通过 p 访问第 i 个对象的成员,如 show() , set(char *name,char *gender, int age) 等公有成员。

p 是指针, p+i 也是指针。指针指向 ->
*p 是对象, *(p+i) 也是对象,对象用访问 .

(*(p+i)).show()
(p+i)->show()
  1. 指向类中成员函数的指针如何定义?它与一般函数指针定义的区别是什么?

一般函数指针的调用与类中的静态成员函数并无区别。因为类的静态成员不属于任何对象。 但与类的非静态成员函数指针有区别。因为类的非静态成员函数中有一个隐形的 this 指针,使得其与一般函数指针不兼容。并且类与类之间的 this 指针也是不一样的,也就是指向不同类的非静态成员函数指针间也是不兼容的。因而需要指出非静态成员函数指针所属的类,即在指针前需要加上参数名,表示指针是指向某一类的非静态成员函数。

  1. this 指针与对象指针的区别是什么?this 指针的用途?
  • this 指针:在每一个成员函数中都包含一个特殊的指针,这个 this 指针的名字是固定的,称为 this。它是指向本类对象的指针,它的值是当前被调用的成员函数所在的对象的起始地址。
    一个对象的 this 指针并不是对象本身的一部分,不会影响对象的结果。this 作用域是在类内部,编译器自动将对象本身的地址作为一个隐含参数传递给函数。也就是说,即使你没有写上 this 指针,编译器在编译的时候也是加上 this 的,它作为非静态成员函数的隐含形参,对各成员的访问均通过 this 进行。

  • 对象指针:指存放对象初始地址的指针变量。它包括

  1. 指向对象的指针(如 int *p1;//定义指向整型数据的指针变量
  2. 类成员指针,又分为数据成员指针( 类名::*指针变量名=成员地址初值 ,如 Date::*p=d; )和成员函数指针( 函数返回类型 类名::*指针变量名 函数参数 ,如 void (*pf)(char a, const char *b);
  • this 指针与对象指针的区别:this 指针在一般的成员函数内会有,且名字固定,它的值是当前调用该成员函数的对象的地址;对象指针是指向对象的。
  • this 指针的用途:当参数有跟该对象里的成员变量重名的时候,可以用 this 指针来解决变量重名带来的问题。

# 随堂练习

  1. 下面关于构造函数的叙述,正确的是

    • 构造函数不能重载
    • 构造函数只能定义为无参函数
    • 构造函数只能定义为有参函数
    • 构造函数能重载
  2. 构造函数名必须与类名相同。

  3. 构造函数由系统自动调用运行。

  4. 下面关于析构函数的叙述,正确的是

    • 析构函数必须是无参函数
    • 析构函数可以是有参函数
    • 析构函数能够返回函数值
    • 析构函数不是系统自动调用
  5. 析构函数名与类名相同。

  6. p 是指向 PERSON 类对象的指针,则通过 p 访问公有成员函数 show() 的方法是。

    • p.show();
    • p->show();
    • (*p).show();
    • (*p)->show();
  7. this 指针需要事先声明,才能使用。

阅读次数

请我喝[茶]~( ̄▽ ̄)~*

Ruri Shimotsuki 微信支付

微信支付

Ruri Shimotsuki 支付宝

支付宝

Ruri Shimotsuki 贝宝

贝宝