类和对象(下篇)

初始化列表

简介

a.初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个**放在括号中(规定死了)**的初始值或表达式。

b.初始化列表可以认为就是对象成员变量定义的地方(有些成员必须在定义的地方初始化)

1.
例如 const int _n;
		int& _ref;
		
只能在定义的时候初始化;

2.自定义类型成员也必须在初始化列表里初始化;

请添加图片描述

打样

Data (int year =1 ,int month =1 ,int day =1)
:_year(year)
,_month(month)
{
,_day(day)
}

注意点

  1. 每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)
Data()
:_year = 2
,_year = year-------➡️大错特错,成员变量在初始化列表只能初始化一次
  1. 类中包含以下成员,必须放在初始化列表位置进行初始化
    引用成员变量
    const成员变量
    自定义类型成员(该类没有默认构造函数)
1.
class A
{
	A(int a)--------故意不写成默认构造函数
	{}
private:
	int _a;
};	
2.
A就算是有默认构造函数但是若要在Data里初始化A的成员变量
	需要这样!

a.
Data (int year =1, int month =1, int day =1,int a)
	    {
	    	A aa(a);
	    	_aa = aa;
	    	
	    	_aa(a)-----❌:此会说调用operator()函数,所以必须先构造和_aa相同的类型,然后对其进行赋值!
	    }

b.
Data (int year =1, int month =1, int day =1,int a)
	:_aa(a)--------➡️所以他会调用_aa的构造函数 ,效率会比上面那种高一些!
	{......}

class Data
{
public:
	Data (int year =1, int month =1, int day =1,int a)
	    :_aa(a)----------所以必须在初始化列表初始化!
	    ,_year(year)
	    {.....}
private:
A _aa;
};

请添加图片描述
这里的Stack初始化也是在初始化列表里面初始化的。

例题

✳️成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关
请添加图片描述
此处会先对_a2进行初始化。

特殊的隐式类型转换

包含explict 关键字

class Data
{
pubilic:
	explicit Data(int year)--------➡️若没加“explicit”则支持Data d1=2022;否则就不会支持隐式类型转换
	:_year(year)
	{}
	
};
int main()
{
	Data d1(2022);-----➡️就只有“构造”
	Data d2 = 2022;-----➡️按理来说是“构造(先用2022构造一个Data对象)”,然后再用这个对象去“拷贝构造”d2;
	若编译器大胆会优化成合二为一就只有“构造”;
	
	为以后string做铺垫:string s1 = “hello”;
	
	
	const Data& d5 = 2022;-------➡️若不加const 则引用过不去;
	Func(const string& s)--------➡️所以必须要有const{}
	Func("hello);
	return 0;
}

static成员(静态成员)

概念

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

面试题

实现一个类,计算程序中创建了多少个对象

int count = 0;--------➡️不推荐使用全局变量
class A
{
public:
	A()
	{
		count++;
	}

	A(const A& aa)
	{
		count++;
	}

static int GetCount()-------➡️静态成员函数,没有this指针!
{
	_a=0---------❌:因为没有this指针,无法访问非静态成员!

	return _count;
}
privateint _a;
	static int _count;-------➡️静态成员变量属于整个类,属于所有的对象
	
	static int _count=0-------❌:因为静态他不在初始化列表定义,而是在类外
};

int A::_count = 0;--------➡️静态成员必须在类外面定义!

int main()
{
	cout << A:: _count << endl;-------➡️通过类域去访问,但成员变量也得放成公有的,
	否则就写GetCount()函数,但是若没有对象调用的话,
	则要将其定义为静态成员函数
	
	cout<<A::GetCount()<<endl;------➡️无对象
	cout<<a.GetCount()<<endll----➡️有对象
	return 0;
}

特性

  1. 静态成员为所有类对象所共享,不属于某个具体的实例
  2. 静态成员变量必须在类外定义定义时不添加static关键字
  3. 类静态成员即可用类名::静态成员或者对象.静态成员来访问
  4. 静态成员函数没有隐藏的this指针不能访问任何非静态成员
  5. 静态成员和类的普通成员一样也有public、protected、private3种访问级别,也可以具有返回值

有意思的代码题

请添加图片描述
由于不让我循环,则我们调用n此构造函数,所以创建n个对象(可以用数组,也可以new n个对象);

友元

友元函数

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

friend std::ostream& operator <<(std::ostream& out,Data& d);//friend声明的函数不属于类域,此处是全局函数。
若在类里面实现重载流插入/提取则用法会比较不太好。

说明:

1.友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在类的内部声明,声明时需要加friend关键字。
2.友元函数可访问类的私有和保护成员,但不是类的成员函数
3.友元函数不能用const修饰-----➡️因为const修饰的是“this”指针,但友元函数没有用到“this”指针
4.友元函数可以在类定义的任何地方声明,不受类访问限定符限制
5.一个函数可以是多个类的友元函数
6.友元函数的调用与普通函数的调用和原理相同

友元类

打样

class Date; // 前置声明
class Time
{
 	friend class Date;-------➡️声明友元类
 private:
 	int _hour;
 	int _minute;
 	int _second;
};

class Date
{
private:
	int _year;
	int _month;
 	int _day;
 	Time _t;
};

简介

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

内部类(C++很少用)

打样

1.
// 内部类
class A
{
private:
	static int k;
	int h;

//public:
	// 内部类
	class B --------➡️B天生就是A的友元
	{
	public:
		void foo(const A& a)
		{
			cout << k << endl;//OK
			cout << a.h << endl;//OK
		}
	private:
		int _b;
	};

	 ✳️验证A不是B的友元
	void Print(const B& b)
	{
	b._b = 0;------------❌:无法调用B的成员变量 
	
};

2.若要计算A的大小:sizeof(A)
因为创建对象A并没有创建对象B出来,所以首先B的大小不在其内
其次,静态成员变量属于整个类,不在某一个对象空间里面,所以其也不算进大小里面
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
面向对象编程是一种编程范式,它将程序的构建和设计思路以面向对象的方式进行组织和实现。在Java中,面向对象编程是基于Java SE(Standard Edition)的一种编程方式。第07讲主要介绍了面向对象编程中的一些基本概念和关键术语。 在面向对象编程中,我们将程序中的数据和对数据的操作(方法)封装在一起,形成一个对象。对象由两部分构成:属性和方法。属性是用来描述对象的特征,而方法则是对象可以执行的操作。对象之间通过消息(方法调用)进行通信和交互。面向对象的核心思想是通过封装、继承和多态实现程序的复用和扩展。 封装是面向对象编程中的一个重要概念,它指的是将类的属性和方法进行封装,使得外部无法直接访问和修改对象的内部状态,只能通过公共的方法来操作属性和执行方法。封装提供了一种将数据和行为组合在一起的方式,可以保护数据的完整性和安全性。 继承是面向对象编程中的另一个重要概念,它指的是通过定义一个新的类来继承现有类的属性和方法。通过继承,子类可以继承父类的属性和方法,并可以在此基础上进行扩展和修改。继承提供了一种代码复用的机制,可以减少重复编码的工作量。 多态是面向对象编程的又一个重要概念,它指的是同一类型的对象在不同的情况下可以有不同的表现形式。多态通过方法的重写和方法的重载实现。方法的重写指的是在子类中重新定义和实现父类的方法,方法的重载指的是在同一个类中可以定义多个同名但参数列表不同的方法。 总结来说,面向对象编程是一种将程序组织和设计思路以对象为中心的编程方式。在JavaSE中,我们可以通过封装、继承和多态来实现面向对象编程的目标。封装可以提高程序的可维护性和可复用性,继承可以减少重复编码的工作量,多态可以灵活地操作对象。掌握这些基本概念和关键术语,可以帮助我们更好地理解和应用面向对象编程的思想。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值