当前位置:网站首页>类与对象 (下)
类与对象 (下)
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(外部类)=外部类,和内部类没有任何关系
边栏推荐
猜你喜欢
Redis + NodeJS 实现一个能处理海量数据的异步任务队列系统
arcgis制图之天地图符号样式配置
【报错记录】解决华擎J3455-ITX不插显示器无法开机的问题
mongodb学习笔记
[项目配置] 配置Qt函数库和ui界面库的封装并调用的项目
Dialogue with the DPO of a multinational consumer brand: How to start with data security compliance?See you on 8.11 Live!
ESIM(Enhanced Sequential Inference Model)- 模型详解
Qt 国际化翻译
上传张最近做的E2用的xmms的界面的截图
想了解API接口,这一篇就够了
随机推荐
Probably 95% of the people are still making PyTorch mistakes
unix环境编程 第十五章 15.6 XSI IPC
json库的dumps()方法和loads()方法
多行省略和选择器
笔记本电脑使用常见问题,持续更新
Win32控件--------------------WM_DRAWITEM消息测试程序
[项目配置] 配置Qt函数库和ui界面库的封装并调用的项目
深度学习--循环神经网络(Recurrent Neural Network)
山东招远通报星童幼儿园食品安全问题最新调查情况
snmp++编译错误问题解决方法
Umi Hooks
day16_03集合
[贴装专题] 贴装流程中涉及到的位置关系计算
[Original] Usage of @PrePersist and @PreUpdate in JPA
jvm-类加载系统
在犹豫中度过了老多天,今天的工作时记录
unix环境编程 第十五章 15.10 POSIX信号量
numpy的ndarray取数操作
Unix Environment Programming Chapter 15 15.9 Shared Storage
对话跨国消费品牌DPO:数据安全合规从何做起?8.11直播见!