当前位置: 首页 > article >正文

C++复试笔记(三)

1.友元函数和友元类

1.1友元函数

友元函数的经典实例是重载 "<<" 和 ">>" ,去重载operator<<,然后发现没办法将operator<<重载成成员函数。因为cout输出流对象和隐含的this指针在抢占第一个参数的位置this指针默认是第一个参数也就是左操作 数了。但是实际使用中cout需要是第一个形参对象,才能正常使用。所以要将operator<<重载成 全局函数。但又会导致类外没办法访问成员,此时就需要友元来解决。operator>>同理。

友元函数 可以 直接访问 类的 私有 成员,它是 定义在类外部 普通函数 ,不属于任何类,但需要在
类的内部声明,声明时需要加 friend 关键字。
class Date
{
     friend ostream& operator<<(ostream& _cout, const Date& d);
     friend istream& operator>>(istream& _cin, Date& d);
public:
     Date(int year = 1900, int month = 1, int day = 1)
         : _year(year)
         , _month(month)
         , _day(day)
         {}
private:
     int _year;
     int _month;
     int _day;
};
ostream& operator<<(ostream& _cout, const Date& d)
{
     _cout << d._year << "-" << d._month << "-" << d._day;
     return _cout; 
}
istream& operator>>(istream& _cin, Date& d)
{
     _cin >> d._year;
     _cin >> d._month;
     _cin >> d._day;
     return _cin;
}
int main()
{
     Date d;
     cin >> d;
     cout << d << endl;
     return 0;
}

说明:

  • 友元函数可访问类的私有和保护成员,但不是类的成员函数
  • 友元函数不能用const修饰
  • 友元函数可以在类定义的任何地方声明,不受类访问限定符限制
  • 一个函数可以是多个类的友元函数
  • 友元函数的调用与普通函数的调用原理相同

1.2友元类

  • 友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。
  • 友元关系是单向的,不具有交换性。

         比如上述Time类和Date类,在Time类中声明Date类为其友元类,那么可以在Date类中直接

         访问Time类的私有成员变量,但想在Time类中访问Date类中私有的成员变量则不行。

  • 友元关系不能传递

         如果CB的友元, BA的友元,则不能说明CA的友元。

  • 友元关系不能继承。
class Time
{
   friend class Date;   // 声明日期类为时间类的友元类,则在日期类中就直接访问Time类
中的私有成员变量
public:
 Time(int hour = 0, int minute = 0, int second = 0)
 : _hour(hour)
 , _minute(minute)
 , _second(second)
 {}
   
private:
   int _hour;
   int _minute;
   int _second;
};
class Date
{
public:
   Date(int year = 1900, int month = 1, int day = 1)
       : _year(year)
       , _month(month)
       , _day(day)
   {}
   
   void SetTimeOfDate(int hour, int minute, int second)
   {
       // 直接访问时间类私有的成员变量
       _t._hour = hour;
       _t._minute = minute;
       _t._second = second;
   }
   
private:
   int _year;
   int _month;
   int _day;
   Time _t;
};

2.解引用和后置++

int main()
{
	int a[10] = { 0,1,-2,3,-4,5,-6,7,-8,9 }, * p = a + 1;
	cout << *p++ << endl;
	return 0;
}

  1. 然后,定义了一个指向整型的指针 p 并将其初始化为 a + 1。这里,a 是数组名,也可以作为指向数组第一个元素的指针使用。所以,a + 1 就是指向数组第二个元素的指针(即指向值为 1 的那个元素)。

  2. cout << *p++ << endl; 这行代码执行了以下操作:

    • *p:首先解引用指针 p,得到它当前指向的值,这里是 1
    • p++:然后,执行 p 的自增操作,使 p 指向下一个元素。但是需要注意的是,根据C++运算符优先级,p++ 在此上下文中是在 *p 获取值之后才进行的,这意味着这次自增不会影响本次解引用的结果。

    因此,最终输出的是 1,这是 p 初始指向位置的值。在输出之后,p 将会指向数组中的下一个元      素 -2,但这个变化不影响已经输出的结果。

3.数组指针

int main()
{

	int a[][3] = { 1,-2,3,-4,5,-6 }, (*p)[3] = a + 1;
	cout << **p << endl;
	return 0;
}

  • (*p)[3] = a + 1;

首先要明确的是,p是一个指针,因为加上了()。这里定义了一个指针 p,它指向一个包含3个整数的数组。a + 1 指向数组 a 的第二行(即 a[1]),因此 p 直接指向了 a 的第二行。

4.new对象要显示调用析构函数

#include<iostream>
#include<string>
using namespace std;
class Person {
private:
	int age;
public:
	string name;
	Person(int a, string n = "Hqu") {
		age = a;
		name = n;
		cout << "constructing..." << n << endl;
	}
	~Person() {
		cout << name << "being destructed!" << endl;
	}

};
int main() {
	Person* p1 = new Person(19, "BUAA");
	Person p2(50, "dong");
	return 0;
}

当你使用 new 来分配内存时,需要显式地使用 delete 来释放这块内存,否则析构函数不会被调用,导致可能的内存泄漏。

而普通构造函数,在程序结束后会自动调用析构函数。

5.前置++、后置++和短路

int main()
{
	int i = 1, j = 0;
	if (--i && j++)
	//if(j++ && --i)
		cout << i << "," << j << endl;
	else
		cout << i << "," << j << endl;

	return 0;
}

关键在于理解if (--i && j++)这一行。这里使用了逻辑与(&&)运算符,它具有短路特性。具体来说,当且仅当左侧表达式为真(非零)时,才会计算右侧表达式。在这个例子中:

  1. --i:首先执行,将i从1减到0。此时--i的结果是0。
  2. 因为--i的结果是0(即假),根据&&运算符的短路特性,程序不会计算&&后面的j++部分,因为无论j++的结果是什么,整个表达式的最终结果都已经是假了(只要&&左边的操作数为假,整个表达式就为假)。

因此,在这个特定情况下,尽管if语句的条件判断导致执行了else分支,但由于j++并未被执行(由于短路),j的值并不会增加。所以,输出结果仍然是:0,0

int main()
{
	int i = 1, j = 0;
	//if (--i && j++)
	if(j++ && --i)
		cout << i << "," << j << endl;
	else
		cout << i << "," << j << endl;

	return 0;
}

调整了条件判断的顺序,现在逻辑表达式是 if(j++ && --i)。这个变化很重要,因为它影响了短路求值的行为和操作符的执行情况。

  1. 首先定义两个整数变量 i 和 j,并分别初始化为 1 和 0
  2. 在 if 语句中,首先计算 j++。这里需要注意的是,j++ 是后置递增操作,意味着它会先使用 j 的当前值(这里是 0)进行逻辑与运算,然后再将 j 增加1。
  3. 因为 j++ 使用的是 j 的原始值 0,所以 j++ && --i 这个表达式的左部分已经是 false(即0)。根据逻辑与运算的短路特性,一旦确定左边为假,则不会评估右边的表达式。因此,--i 不会被执行。
  4. 尽管 --i 没有被执行,但由于 j++ 的存在,j 的值会在这一行结束后增加到 1

因此,程序将会输出 ij 的值,其中 i 保持不变,因为 --i 没有被执行;而 j 则由于 j++ 而从 0 变成了 1。最终输出结果将是:1,1


http://www.kler.cn/a/584017.html

相关文章:

  • uniapp 实现的步进指示器组件
  • C++设计模式-原型模式:从基本介绍,内部原理、应用场景、使用方法,常见问题和解决方案进行深度解析
  • OpenHarmony 编译运行qemu模拟设备
  • MyBatis 中SQL 映射文件是如何与 Mapper 接口关联起来的? MyBatis 如何知道应该调用哪个 SQL 语句?
  • Tomcat新手入门指南:从零开始搭建Web服务器
  • SSR 框架是什么?
  • 使用 OpenAI 的 Node.js 通过 Ollama 在本地运行 DeepSeek R1
  • 工厂变电所运维云平台解决方案-直击运维痛点,重塑高效安全运维典范
  • 框架源码私享笔记(02)Mybatis核心框架原理 | 一条SQL透析核心组件功能特性
  • 过滤器(Filter)与拦截器(Interceptor)
  • 【Git】所有文章传送门(持续更新...)
  • eNSP中路由器的CON/AUX接口、GE Combo接口、Mini USB接口、USB接口、WAN侧uplink接口、FE接口、GE接口介绍
  • C++程序员职业规划
  • IP层之分片包的整合处理---BUG修复
  • celery入门
  • 大模型架构记录5-向量数据库
  • AutoSar架构-----XCP模块与协议介绍
  • 【Jmeter】使用教程
  • 基于WPF的雷达上位机系统开发实践
  • 【算法】蒙特卡洛树搜索(MCTS)算法