类和对象深入理解

目录

  • static成员
    • 概念
      • 静态成员变量
        • 面试题
        • 补充
          • 代码1
          • 代码2
          • 代码3
          • 如何访问private中的成员变量
      • 静态成员函数
        • 静态成员函数没有this指针
    • 特性
  • 友元
    • 友元函数
    • 友元类
  • 内部类
    • 特性1
    • 特性2
  • 匿名对象
  • 拷贝对象时的一些编译器优化

感谢各位大佬对我的支持,如果我的文章对你有用,欢迎点击以下链接
🐒🐒🐒 个人主页
🥸🥸🥸 C语言
🐿️🐿️🐿️ C语言例题
🐣🐣🐣 python
🐓🐓🐓 数据结构C语言
🐔🐔🐔 C++
🐿️🐿️🐿️ 文章链接目录

static成员

概念

声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量
用static修饰的成员函数,称之为静态成员函数。
静态成员变量一定要在类外进行初始化

静态成员变量

面试题

面试题:实现一个类,计算程序中创建出了多少个类对象。

class A
{
public:
	A()
	{
		++n;
	}
	A(const A& aa)
	{
		++ n;
	}
private:
	static int n;
}; 
int A::n = 0;

这里的n就是一个静态全局变量,注意静态变量是不能给缺省值的,因为他不是单独属于某一个对象,而是属于这个类的所有对象,因此需要在类外面定义

由于n受域作用限定符的限制,当我们屏蔽掉private后就可以访问n了
在这里插入图片描述

我们再来看看下面的三段代码

补充
代码1
class A
{
public:
	A()
	{
		++n;
	}
	A(const A& aa)
	{
		++ n;
	}
//private:
	static int n;
}; 
int A::n = 0;
int main()
{
	A aa1;
	A aa2;
	A* ptr = nullptr;
	cout << aa1.n << endl;
	cout << aa2.n << endl;
	cout << ptr->n << endl;
	return

在这里插入图片描述

代码2
class A
{
public:
	A()
	{
		++n;
	}
	A(const A& aa)
	{
		++ n;
	}
//private:
	static int n;
}; 
int A::n = 0;
int main()
{
	A aa1;
	//A aa2;
	A* ptr = nullptr;
	cout << aa1.n << endl;
	//cout << aa2.n << endl;
	cout << ptr->n << endl;
	return 0;
}

在这里插入图片描述

代码3
class A
{
public:
	A()
	{
		++n;
	}
	A(const A& aa)
	{
		++ n;
	}
//private:
	static int n;
}; 
int A::n = 0;
int main()
{
	//A aa1;
	//A aa2;
	A* ptr = nullptr;
	//cout << aa1.n << endl;
	//cout << aa2.n << endl;
	cout << ptr->n << endl;
	return 0;
}

在这里插入图片描述
上面的三个代码中ptr输出的n的值是不一样的,这需要我们了解static存储的变量在静态区
比如ptr->n,n并不在ptr指向的对象里,而是在静态区,在寻找n的时候就是去静态区里找
因为是受到static修饰,所以n的值是全局变量,全局变量不想局部变量,出了作用域后就会销毁然后从新开始,也就是说这里的n不会因为一个对象结束后就重新变成0

如何访问private中的成员变量

上面的代码中我们都是将private屏蔽掉才可以访问到n的,当private没有屏蔽的时候,就会因为权限导出不允许访问
在这里插入图片描述
要想解决这个问题只有在公有区域里创建一个函数Getn()去获得n的值

class A
{
public:
	A()
	{
		++n;
	}
	A(const A& aa)
	{
		++ n;
	}
	int Getn()
	{
		return n;
	}
private:
	static int n;
}; 
int A::n = 0;
int main()
{
	A aa1;
	cout << aa1.Getn() << endl;
	return 0;
}

在这里插入图片描述

静态成员函数

静态成员函数的访问方式如下
在这里插入图片描述
A::Getn()也是可以这样访问的,另外静态成员变量也同理
在这里插入图片描述

静态成员函数没有this指针

静态成员函数与普通的成员函数不同点在于静态成员函数没有this指针,所以不能访问非静态成员变量或者函数

class A
{
public:
	A()
	{
		++n;
	}
	A(const A& aa)
	{
		++ n;
	}
	static int Getn()
	{
		a++;
		return n;
	}
private:
	static int n;
	int a;
}; 
int A::n = 0;
int main()
{
	A aa1;
	cout << A::n << endl;
	return 0;
}

在这里插入图片描述

特性

1. 静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区
2. 静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明
3. 类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问
4. 静态成员函数没有隐藏的this指针,不能访问任何非静态成员
5. 静态成员也是类的成员,受public、protected、private 访问限定符的限制

友元

友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以
友元不宜多用。所以友元我们了解一下就行了
友元分为:友元函数和友元类

友元函数

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

class Date
{
public:
 Date(int year, int month, int day)
     : _year(year)
     , _month(month)
     , _day(day)
 {}
 // d1 << cout; -> d1.operator<<(&d1, cout); 不符合常规调用
 // 因为成员函数第一个参数一定是隐藏的this,所以d1必须放在<<的左侧
 ostream& operator<<(ostream& _cout)
 {
     _cout << _year << "-" << _month << "-" << _day << endl;
     return _cout;
 }
private:
 int _year;
 int _month;
 int _day;
};

友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在
类的内部声明,声明时需要加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修饰(没有this指针)
友元函数可以在类定义的任何地方声明,不受类访问限定符限制
一个函数可以是多个类的友元函数
友元函数的调用与普通函数的调用原理相同

友元类

友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。
友元关系是单向的,不具有交换性。
比如上述Time类和Date类,在Time类中声明Date类为其友元类,那么可以在Date类中直接
访问Time类的私有成员变量,但想在Time类中访问Date类中私有的成员变量则不行。
友元关系不能传递
如果C是B的友元, B是A的友元,则不能说明C时A的友元。友元关系不能继承

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;
};

内部类

概念:如果一个类定义在另一个类的内部,这个内部类就叫做内部类。内部类是一个独立的类,
它不属于外部类,更不能通过外部类的对象去访问内部类的成员。外部类对内部类没有任何优越
的访问权限。

注意:内部类就是外部类的友元类,内部类可以通过外部类的对象参数来访问外部类中的所有成员
但是外部类不是内部类的友元。

特性:
1. sizeof(外部类)=外部类,和内部类没有任何关系。
2. 内部类可以定义在外部类的public、protected、private都是可以的,且内部类受类域限制
3. 注意内部类可以直接访问外部类中的static成员,不需要外部类的对象/类名(内部类是外部类的友元类)

特性1

class A
{
private:
    static int k;
    int h;
public:
    class B // B天生就是A的友元
    {
    public:
        void foo(const A& a)
        {
            cout << k << endl;
            cout << a.h << endl;
        }
    };
};
int A::k = 1;
int main()
{
    A::B b;
    b.foo(A());
    cout << sizeof(A) << endl;

    return 0;
}

在这里插入图片描述

sizeof(A)的结果是4,可能很多人会觉得B在A里面的,所以sizeof(A)的结果是包含了B的空间的,但是事实上不是这样的,如果要让sizeof(A)的结果是算上B的空间大小的话应该像下面这段代码这样写

class B
{
private:
    int _b1;
};
class A
{
private:
    static int k;
    int h;
    B _b;
}

此外类是不占用空间的,因为类只是一个声明,而在定义的时候才会有空间,也就是说声明只是说有这么一个东西,但是不会讲空间分配给他,而定义则是让这个东西真实的存在,并分配空间给他

特性2

内部类也是受访问限定符和类域的限制

class A
{
public:
        class B
        {

        };
};
int main()
{
    A a;
    B b;
    return 0;
}

在这里插入图片描述
当我们用域作用限定符的时候就可以正常运行

class A
{
public:
        class B
        {

        };
};
int main()
{
    A a;
    A::B b;
    return 0;
}

在这里插入图片描述
但是当class B 在A的private中就会因为B是私有导致无法访问

class A
{
private:
        class B
        {

        };
};
int main()
{
    A a;
    A::B b;
    return 0;
}

在这里插入图片描述

匿名对象

匿名对象就是没有名字的对象,他的特点是生命周期只在当前一行

class A
{
public:
	A(int a = 0)
		:_a(a)
	{
		cout << "A(int a)" <<a<< endl;
	}
	~A()
	{
		cout << "~A()" << endl;
	}
private:
	int _a;
};
int main()
{
	A aa1;
	A aa2(2);
	A();
	A(3);
	return 0;
}

在这里插入图片描述

拷贝对象时的一些编译器优化

在传参和传返回值的过程中,一般编译器会做一些优化,减少对象的拷贝,这个在一些场景下还
是非常有用的。
但是不同的编译器优化程度是不同的,所以我们只需要简单了解一下就可以了

class A
{
public:
 A(int a = 0)
 :_a(a)
 {
 cout << "A(int a)" << endl;
 }
 A(const A& aa)
 :_a(aa._a)
 {
 cout << "A(const A& aa)" << endl;
 }
 A& operator=(const A& aa)
 {
 cout << "A& operator=(const A& aa)" << endl;
 if (this != &aa)
 {
 _a = aa._a;
 }
 return *this;
 }
 ~A()
 {
 cout << "~A()" << endl;
 }
private:
 int _a;
};
void f1(A aa)
{}
A f2()
{
 A aa;
 return aa;
}
int main()
{
 // 传值传参
 A aa1;
 f1(aa1);
 cout << endl;
 // 传值返回
 f2();
 cout << endl;
 // 隐式类型,连续构造+拷贝构造->优化为直接构造
 f1(1);
 // 一个表达式中,连续构造+拷贝构造->优化为一个构造
 f1(A(2));
 cout << endl;
 // 一个表达式中,连续拷贝构造+拷贝构造->优化一个拷贝构造
 A aa2 = f2();
 cout << endl;
 // 一个表达式中,连续拷贝构造+赋值重载->无法优化
 aa1 = f2();
 cout << endl;
 return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/776663.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++ | Leetcode C++题解之第217题存在重复元素

题目&#xff1a; 题解&#xff1a; class Solution { public:bool containsDuplicate(vector<int>& nums) {unordered_set<int> s;for (int x: nums) {if (s.find(x) ! s.end()) {return true;}s.insert(x);}return false;} };

【PB案例学习笔记】-27制作一个控制任务栏显示与隐藏的小程序

写在前面 这是PB案例学习笔记系列文章的第27篇&#xff0c;该系列文章适合具有一定PB基础的读者。 通过一个个由浅入深的编程实战案例学习&#xff0c;提高编程技巧&#xff0c;以保证小伙伴们能应付公司的各种开发需求。 文章中设计到的源码&#xff0c;小凡都上传到了gite…

视频参考帧和重构帧复用

1、 视频编码中的参考帧和重构帧 从下图的编码框架可以看出&#xff0c;每编码一帧需要先使用当前帧CU(n)减去当前帧的参考帧CU&#xff08;n&#xff09;得到残差。同时&#xff0c;需要将当前帧的重构帧CU*&#xff08;n&#xff09;输出&#xff0c;然后再读取重构帧进行预测…

Pandas数据可视化详解:大案例解析(第27天)

系列文章目录 Pandas数据可视化解决不显示中文和负号问题matplotlib数据可视化seaborn数据可视化pyecharts数据可视化优衣库数据分析案例 文章目录 系列文章目录前言1. Pandas数据可视化1.1 案例解析&#xff1a;代码实现 2. 解决不显示中文和负号问题3. matplotlib数据可视化…

HTTP代理服务器:深度解析与应用

“随着互联网的飞速发展&#xff0c;HTTP代理服务器在网络通信中扮演着越来越重要的角色。它们作为客户端和服务器之间的中介&#xff0c;不仅优化了网络性能&#xff0c;还提供了强大的安全性和隐私保护功能。” 一、HTTP代理服务器的概念与作用 HTTP代理服务器是一种能够接…

Qt扫盲-QRect矩形描述类

QRect矩形描述总结 一、概述二、常用函数1. 移动类2. 属性函数3. 判断4. 比较计算 三、渲染三、坐标 一、概述 QRect类使用整数精度在平面中定义一个矩形。在绘图的时候经常使用&#xff0c;作为一个二维的参数描述类。 一个矩形主要有两个重要属性&#xff0c;一个是坐标&am…

前端面试题16(跨域问题)

跨域问题源于浏览器的同源策略&#xff08;Same-origin policy&#xff09;&#xff0c;这一策略限制了来自不同源的“写”操作&#xff08;比如更新、删除数据等&#xff09;&#xff0c;同时也限制了读操作。当一个网页尝试请求与自身来源不同的资源时&#xff0c;浏览器会阻…

设计模式探索:代理模式

1. 什么是代理模式 定义 代理模式是一种结构型设计模式&#xff0c;通过为其他对象提供一种代理以控制对这个对象的访问。代理对象在客户端和实际对象之间起到中介作用&#xff0c;可以在不改变真实对象的情况下增强或控制对真实对象的访问。 目的 代理模式的主要目的是隐…

着急,为啥AI叫好不叫座啊?

关注卢松松&#xff0c;会经常给你分享一些我的经验和观点。 李彦宏在2024世界人工智能大会上说&#xff1a; 没有应用&#xff0c;光有基础模型&#xff0c;不管是开源还是闭源都一文不值&#xff0c;所以我从去年下半年开始讲&#xff0c;大家不要卷模型了&#xff0c;要去…

MySQL---事务管理

1.关于事务 理解和学习事务&#xff0c;不能只站在程序猿的角度来理解事务&#xff0c;而是要站在使用者&#xff08;用户&#xff09;的角度来理解事务。 比如支付宝转账&#xff0c;A转了B100块前&#xff0c;在程序猿的角度来看&#xff0c;是两条update操作&#xff0c;A …

PCDN技术如何提高内容分发效率?(贰)

PCDN技术通过以下方式提高内容分发效率: 1.利用用户设备作为分发节点:与传统的 CDN技术主要依赖中心化服务器不同&#xff0c; PCDN技术利用用户的设备作为内容分发的节点。当用户下载内容时&#xff0c;他们的设备也会成为内容分发的一部分&#xff0c;将已下载的内容传递给其…

项目部署_持续集成_Jenkins

1 今日内容介绍 1.1 什么是持续集成 持续集成&#xff08; Continuous integration &#xff0c; 简称 CI &#xff09;指的是&#xff0c;频繁地&#xff08;一天多次&#xff09;将代码集成到主干 持续集成的组成要素 一个自动构建过程&#xff0c; 从检出代码、 编译构建…

树状数组实现 查找逆序对

题意&#xff1a; 输入一个整数n。 接下来输入一行n个整数 。 1< < n ,且每个数字只会出现一次 题解&#xff1a; 按每个数字的大小存入树状数组 #include<bits/stdc.h> using namespace std; #define ll long long const int N10000; int arr[N]; ll a[N];…

Java中关于构造代码块和静态代码块的解析

构造代码块 特点&#xff1a;优先于构造方法执行,每new一次,就会执行一次 public class Person {public Person(){System.out.println("我是无参构造方法");}{System.out.println("我是构造代码块"); //构造代码块} }public class Test {public stati…

golang与以太坊交互

文章目录 golang与以太坊交互什么是go-ethereum与节点交互前的准备使用golang与以太坊区块链交互查询账户的余额使用golang生成以太坊账户使用golang生成以太坊钱包使用golang在账户之间转移eth安装使用solc和abigen生成bin和abi文件生成go文件使用golang在测试网上部署智能合约…

GD32MCU如何实现掉电数据保存?

大家在GD32 MCU应用时&#xff0c;是否会碰到以下应用需求&#xff1a;希望在MCU掉电时保存一定的数据或标志&#xff0c;用以记录一些关键的数据。 以GD32E103为例&#xff0c;数据的存储介质可以选择内部Flash或者备份数据寄存器。 如下图所示&#xff0c;片内Flash具有10年…

【综合能源】计及碳捕集电厂低碳特性及需求响应的综合能源系统多时间尺度调度模型

目录 1 主要内容 2 部分程序 3 实现效果 4 下载链接 1 主要内容 本程序是对《计及碳捕集电厂低碳特性的含风电电力系统源-荷多时间尺度调度方法》方法复现&#xff0c;非完全复现&#xff0c;只做了日前日内部分&#xff0c;并在上述基础上改进升级为电热综合电源微网系统&…

力扣习题--找不同

目录 前言 题目和解析 1、找不同 2、 思路和解析 总结 前言 本系列的所有习题均来自于力扣网站LeetBook - 力扣&#xff08;LeetCode&#xff09;全球极客挚爱的技术成长平台 题目和解析 1、找不同 给定两个字符串 s 和 t &#xff0c;它们只包含小写字母。 字符串 t…

智能光伏开发都能用到什么软件和工具?

随着全球对可再生能源的日益重视和光伏技术的快速发展&#xff0c;智能光伏开发已成为推动能源转型的重要力量。在光伏项目的全生命周期中&#xff0c;从设计、建设到运营管理&#xff0c;各种软件和工具的应用发挥着至关重要的作用。 一、光伏系统设计软件 1、PVsyst PVsyst…

Python创建MySQL数据库

一、使用Docker部署本地MySQL数据库 docker run --restartalways -p 3307:3306 --name mysql -e MYSOL_ROOT_PASSWORDlms123456 -d mysql:8.0.25 参数解析: 用户名:root 密码:lms123456 端口:3307 二、在Pycharm开发工具中配置连接MySQL数据库 三、安装zdppy_mysql pip inst…