当前位置:网站首页>类与对象 (下)
类与对象 (下)
2022-08-09 10:36:00 【迷茫中的小伙】
一、<<(流插入) 重载及友元函数初学
我们经常用cout << 10<< endl;输出的结果是10
那么我们可以打印我们自定义的对象吗?
当然可以,只需要我们重载一下流插入成员函数即可.
void Date::operator<<(ostream& out)//cout是一个ostream类型的对象
{
out << _year <<" --" << _month << "--" << _day << endl;
}
int main()
{
d1.operator<<(cout);//&d1,cout
d1 << cout;//为什么不写成cout<<d1;因为因为是成员函数,&cout是this指针,而d1是参数,就与成员函数参数不对应
}
但是d1<<cout;又不符合我们所学的习惯,因此有第二种方法,可以不讲<<重载函数写成成员函数.可以直接将它写成全局的函数.
但是此时,我们我们无法调用类中的私有成员变量
此时,就引入了一个新的访问私有成员变量的方法:友元函数
即在类中输入
friend void operator<<(ostream& out, const Date& d1);
即让类知道,我是你的朋友,即可访问里面的私有成员变量了
此时又出现了一个问题,我们平常的cout时可以连续输出的,那么这里可以吗?
这里时不可以的,因为cout<<d1,返回为void,void << d2,无法再打印
那么解决的办法就是将void该为ostream&,return cout,那么打印完d1后,返回cout,既可以继续打印cout<<d2了.
ostream& operator<<(ostream& out, const Date& d1) { out << d1._year << " --" << d1._month << "--" << d1._day << endl; return out; }
相应的流提取重载:
istream& operator>>(istream& in, Date& d1) { in >> d1._year >> d1._month >> d1._day; return in; }
二、初始化列表
在创建对象时,编译器会调用各自的构造函数进行初始化,虽然上述对象中已经有了一个初始值,但是这只能称之为赋值,并不能称之为初始化,因为初始化只能有一次,而构造函数体内可以赋值多次,并且当声明成员变量时,const int k ;无法再定义,所以因为这些原因我们引入了初始化列表的概念:
初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括号中的初始值或表达式。
class Date { private://声明 int _year; int _month; int _day; const int k; public: //初始化列表:成员变量初始化的地方 Date(int year, int month, int day) :_year(year)//定义的时候就定义 , _month(month) , _day(day) , k(10) { //定义在里面,就是先定义后给值,比如_year等定义在外面和里面都可以 } }; int main() { Date d1(2022,8,3); }
此时即可初始化带const的成员变量。
注意:
(1)每个成员变量在初始化列表中初始化一次
(2)类中的①引用成员变量②const成员变量③自定义成员(该类没有默认构造函数)的必须放在初始化列表位置进行初始化
总结:
内置类型的成员,在函数体和在初始化列表初始化都可以
自定义类型的成员,建议在初始化列表初始化,这样更高效
2.1 牛刀小试
class A {
public:
A(int a)
:_a1(a)
,_a2(_a1)
{}
void Print()
{
cout<<_a1<<" "<<_a2<<endl;
}
private:
int _a2;
int _a1; }int main()
{
A aa(1);
aa.Print();
}
A. 输出1 1
B.程序崩溃
C.编译不通过
D.输出1 随机值
解析:
此题选择D选项,用到的是一个语法:成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关
三、 隐式类型转换
隐式类型转换这种方式让我们就感觉有些突兀,所以C++又引入了一个关键字"explicit",用explicit修饰构造函数,用来禁止单参构造函数的隐式转换:
四、static
声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用static修饰的成员函数,称之为静态成员函数。静态的成员变量一定要在类外进行初始化
4.1 牛刀小试
class sum
{
public:
//默认构造函数
sum()
{
i += j;
j++;
}
static int getsum()
{
return i;
}
private:
static int i;
static int j;
};
int sum::i = 0;//用来计数
int sum::j = 1;
class Solution {
public:
int Sum_Solution(int n)
{
//创造n个sum类的数组,每实例化一个数组就会调用构造函数为他初始化一次
sum a[n];//变长数组
//return sum().getsum() -(n+1);//匿名类,相当于又创建了一个实例,所以又增加了一个构造
return sum::getsum();
}
};
五、 C++11的补丁
下面的代码:默认的构造函数对内置类型不进行初始化,但是对于自定义类型会去调用它的默认构造函数,这是之前所学的,这就让我们觉得有些不方便,所以C++11对此做了一个补丁
补丁就是在成员变量声明的时候给变量一个缺省值
但如果默认成员变量给_a进行了初始化,那么这个缺省值就不会有效,如果写了默认成员函数,但是初始化列表没有对他进行初始化,也会默认为缺省值
成员变量可以定义缺省值的种类
class B
{
public:
B(int a)
{
_a = a;
}
private :
int _a;
};
class A
{
public:
A(int a)
{
_a = a;
}
private:
int _a = 0;//这里不是初始化,因为这里是声明,给成员变量的是缺省值
B _b = 10;
B _b1 = B(20);
int* p = (int*)malloc(4*10);
int arr[10] = {1,2,3,4,5};
//静态成员变量不能这样给缺省值,必须在类外面全局位置定义初始化
/*static int _count = 0;*///err
};
int A::_count = 0;
int main()
{
A d1(1);
}
六、友元函数
友元分为:友元函数和友元类友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多用。(1) 友元函数可访问类的私有和保护成员,但不是类的成员函数 ,一般就是全局函数(2)友元函数不能用const修饰(3)友元函数可以在类定义的任何地方声明,不受类访问限定符限制(4)一个函数可以是多个类的友元函数(5)友元函数的调用与普通函数的调用和原理相同
6.1友元类
(1)友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。(2)友元关系是单向的,不具有交换性,比如上述Time类和Date类,在Time类中声明Date类为其友元类,那么可以在Date类中直接访问Time(3)类的私有成员变量,但想在Time类中访问Date类中私有的成员变量则不行。(4)友元关系不能传递如果B是A的友元,C是B的友元,则不能说明C是 A的友元。
七、内部类
概念:如果一个类定义在另一个类的内部,这个内部类就叫做内部类。注意此时这个内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去调用内部类。外部类对内部类没有任何优越的访问权限。
注意:内部类就是外部类的友元类。注意友元类的定义,内部类可以通过外部类的对象参数来访问外部类中的所有成员。但是外部类不是内部类的友元。
1.内部类B和在全局定义是基本一样的,只是它受外部类A的限制,只是定义在A的类域中,内部类可以定义在外部类的public、protected、private都是可以的
2.内部类B天生就是外部类A的友元,也就是B中可以访问A的私有,A不能访问B的私有,内部类可以直接访问外部类中的static、枚举成员,不需要外部类的对象/类名。3.sizeof(外部类)=外部类,和内部类没有任何关系
边栏推荐
- ESIM(Enhanced Sequential Inference Model)- 模型详解
- Restful WebServices 学习笔记
- Redis + NodeJS 实现一个能处理海量数据的异步任务队列系统
- 今天做了手机播放器的均衡器
- MySQL外键在数据库中的作用
- stimulus.js 初体验
- 分类预测 | MATLAB实现CNN-GRU(卷积门控循环单元)多特征分类预测
- [Original] Usage of @PrePersist and @PreUpdate in JPA
- 【原创】VMware Workstation实现Openwrt软路由功能,非ESXI,内容非常详细!
- Electron application development best practices
猜你喜欢
【报错记录】解决华擎J3455-ITX不插显示器无法开机的问题
深度学习--循环神经网络(Recurrent Neural Network)
Shell script combat (2nd edition) / People's Posts and Telecommunications Press Script 2 Validate input: letters and numbers only
情感分析SowNLP词库
强化学习 (Reinforcement Learning)
Solve the ali cloud oss - the original 】 【 exe double-click response can't open, to provide a solution
[贴装专题] 视觉贴装平台与贴装流程介绍
学长告诉我,大厂MySQL都是通过SSH连接的
【MySQL】mysql因为字符集导致left join出现Using join buffer (Block Nested Loop)
Cpolar内网穿透的面板功能介绍
随机推荐
The GNU Privacy Guard
By asking where the variables are stored, the shepherd boy laughed and said to use pointers, Go lang1.18 introductory refining tutorial, from Bai Ding to Hongru, the use of go lang type pointers (Poin
【Linux】宝塔面板设置MySQL慢查询日志,未走索引日志
[贴装专题] 视觉贴装平台与贴装流程介绍
Oracle数据库常用函数总结
研发需求的验收标准应该怎么写? | 敏捷实践
OpengGL绘制立方体的三种方法
实现下拉加载更多
hover内部指定子类的样式
Database connection operations for MySQL and MyEclipse
编解码(seq2seq)+注意机制(attention) 详细讲解
Umi Hooks
浅析JWT安全问题
Shell script combat (2nd edition) / People's Posts and Telecommunications Press Script 1 Find programs in the PATH
arcgis制图之天地图符号样式配置
xmms播放器加了播放列表的管理功能
conditional control statement
自启服务mock联调跨域问题
1003 我要通过! (20 分)
源代码阅读器项目