当前位置:网站首页>类与对象 (下)

类与对象 (下)

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  牛刀小试

求1+2+3+...+n_牛客题霸_牛客网

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)友元关系不能传递
如果BA的友元,CB的友元,则不能说明CA的友元。

七、内部类

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

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

1.内部类B和在全局定义是基本一样的,只是它受外部类A的限制,只是定义在A的类域中,内部类可以定义在外部类的publicprotectedprivate都是可以的
2.内部类B天生就是外部类A的友元,也就是B中可以访问A的私有,A不能访问B的私有,内部类可以直接访问外部类中的static、枚举成员,不需要外部类的对象/类名。

3.sizeof(外部类)=外部类,和内部类没有任何关系

原网站

版权声明
本文为[迷茫中的小伙]所创,转载请带上原文链接,感谢
https://blog.csdn.net/qq_53010164/article/details/126127001