lesson04:类和对象(下)

1. 再谈构造函数

2.static成员

3.友元

4.内部类

5.匿名对象

1. 再谈构造函数

1.1构造函数体内赋值

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
class Date
{
public:
	Date(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	return 0;
}

构造函数体种的语句只能将其称为赋值,不能叫做初始化。

它是不能够做到给const数据成员初始化的。

1.2初始化列表

以一个冒号开始,接着是一个以逗号分隔的数据成员列表,没个数据成员后面有一个小括号,括号里面写用于初始化的初始值或表达式

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
class Date
{
public:
	Date(int year, int month, int day)
		: _year(year)//初始值
		, _month(month)
		, _day(day)
		,arr((int*)malloc(sizeof(int)))//表达式
	{}
private:
	int _year;
	int _month;
	const int _day;
	int* arr;
};
int main()
{
	return 0;
}

1.每个数据成员再1初始化列表中只能出现一次(初始化只能进行一次)

2.类中包含以下成员,必须在初始化列表初始化

引用成员变量

const成员变量

自定义类型成员(且没有默认构造函数)

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
class A
{
public:
	A(int a)
		:_a(a)
	{}
private:
	int _a;
};
class B
{
public:
	B(int a, int ref)
		:_aobj(a)
		, _ref(ref)
		, _n(10)
	{}
private:
	A _aobj;// 没有默认构造函数
	int& _ref;// 引用
	const int _n; // const 
};
int main()
{
	B d(1, 2);
	return 0;
}

3.尽量使用初始化列表初始化。

4.成员变量在类中的声明次序就是初始化顺序,初始化与初始化列表中的先后次序无关

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
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();
    return 0;
}

因为_a2是先声明的,所以先对_a2初始化,由于此时_a1还没被初始化,所以_a1是随机值,所以_a2被初始化成了随机值。

5.缺省值与初始化列表的联系

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
class A
{
public:
	void Print() {
		cout << _a1 << " " << _a2 << endl;
	}
private:
	const int _a2 = 1;
	const int _a1 = 2;
};
int main() {
	A aa;
	aa.Print();
    return 0;
}

上面说过,const数据成员一定要在初始化列表初始化,那这里没写,为什么是对的呢?难道是在声明时初始化吗?

解答:

1.编译器默认生成了初始化列表

2.没有声明时初始化这个说法,这种写法是给缺省值,如果不为数据成员指定初始化的内容,那么将使用这个缺省值。所以,编译器是将这个缺省值给到初始化列表,然后再由初始化列表对数据成员初始化。

补充:缺省值也是可以给表达式的

1.3类型转换

内置类型的变量可以通过类型转换变为自定义类型的对象。

而类型转换是通过构造函数实现的。

1.3.1给构造函数传1个参数
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
class Date
{
public:
	int _a;
	Date(int a)
		:_a(a)
	{

	}
};
int main() 
{
	Date d = 3;
	cout << d._a;
	return 0;
}
1.3.2给构造函数传多个参数
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
class Date
{
public:
	int _a;
	int _b;
	Date(int a, int b)
		:_a(a)
		, _b(b)
	{

	}
};
int main() 
{
	Date d = { 3,5 };
	cout << d._a << endl << d._b;
	return 0;
}

1.4explicit关键字

explicit修饰构造函数,禁止类型转换

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
class Date
{
public:
	int _a;
	int _b;
	explicit Date(int a, int b)
		:_a(a)
		, _b(b)
	{

	}
};
int main() 
{
	Date d = { 3,5 };//无法类型转换,报错
	cout << d._a << endl << d._b;
	return 0;
}

2.static成员

2.1概念

用static修饰成员变量,称为静态成员变量; 用static修饰成员函数,称为静态成员函数

2.2特性

1.静态成员所有类对象所共享,不属于某个具体的对象,存放在静态区。

2.静态成员变量必须在类外定义,定义不加static,要使用作用域运算符说明该静态成员变量来自哪个类。注意:类中的只是声明,且静态成员只能在全局定义

3.类静态成员可用类名::静态成员或者对象.静态成员访问。

4.静态成员函数没有this指针,不能访问非静态成员(包括成员函数,调用成员函数也需要this指针)。

5.静态成员也是类的成员,受public,protect,private限制。(定义时无限制)

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
class Date
{
public:
	static int a;
	static void test()
	{
		//cout << c;报错,不能访问非静态成员
		//test1();报错,非静态成员函数也不能
		cout << b;//静态成员可以
		test2();
	}
	static void test2() {};
	void test1() {};
private:
	static int b;
	int c = 1;
};
int Date::a = 5;//类外定义,不加static,用::说明a来源于Date类
int Date::b = 1;//只能在全局初始化
int main() 
{
	Date d;
	cout << Date::a << endl;//类名::静态成员访问
	cout << d.a << endl;//对象.静态成员访问
	//cout << Date::b;报错,受public限制
	return 0;
}

3.友元

友元函数提供了一种突破封装的方式,提供了便利,但同时破坏了封装。(不宜多用

友元分为:友元函数友元类

3.1友元函数

3.1.1概念

友元函数时定义在类外普通函数,不属于任何类,但需要在类内友元声明(和之前的声明一样写,最后在声明开头加上friend)。

3.1.2特性

1.友元函数可以访问类的私有和保护成员

2.一个函数可以是多个类的友元函数

3.友元函数可以在类内任何位置声明,不受private,protect,public限制

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
class Date;//在A类中对test函数友元声明要用到Date,此时Date还为声明
		   //这种写法不算重定义,这么写只是向编译器说明该源文件中有
		   //Date类,和函数的声明一样。
class A
{
	friend void test(const Date& d, const A& t);
private:
	int a = 2;
};
class Date
{
	friend void test(const Date& d, const A& t);
private:
	int a = 1;
	
};
void test(const Date& d, const A& t)
{
	cout << d.a << endl;//访问私有成员
	cout << t.a << endl;
}
int main()
{
	Date d;
	A t;
	test(d, t);
	return 0;
}

注意:编译器通过花括号的有无来判断是声明还是定义,若有花括号,则是定义;若无花括号,则是声明

3.2友元类

3.2.1概念

将一个类在另一个类中友元声明(和之前的声明一样写,最后在声明开头加上friend),那么该类称为另一个类的友元类,该类中的所有成员函数都是另一个类的友元函数

3.2.2特性

1.友元是单向的

如果A是B的友元,不能说明B是A的友元,此时,A能访问B的私有,但B不能访问A的私有

2.友元关系不能传递 

如果C是B的友元,B是A的友元,不能说明C是A的友元

3.友元关系不能继承(以后讲)

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
class A
{
	friend class Date;//友元声明
	int b = 1;
	int a = 2;
};
class Date
{
	int a = 1;
public:
	void test(const A& a)
	{
		cout << a.a << endl << a.b << endl;//访问A类的私有成员
	}
};
int main()
{
	Date d;
	A a;
	d.test(a);
	return 0;
}

4.内部类

4.1概念

如果一个类的定义在另一个类的内部,那么该类就叫内部类。内部类是一个独立的类,不属于任何外部类。

4.2特性

1.内部类可以通过对应外部类的对象访问私有成员。注意:本质上,内部类就是外部类的友元类。但是,外部类不是内部类的友元类。

2.内部类可以直接访问对应外部类的静态成员(不需要通过类名或对象访问,通过类名或对象访问也是对的)

3.对外部类计算大小时,不计入内部类的部分(内部类是一个独立的类,不属于任何外部类。)

4.不能通过外部类的对象直接访问内部类的成员;内部类也不能直接访问外部类的非静态成员(内部类是一个独立的类,不属于任何外部类。)

注意:可以用内部类的对象间接访问

5.内部类受外部类的类域限制(类域类似于命名空间域)

6.内部类受private等访问限定符的限制

总结:友元性,静态直接访问性,受限制性,独立性(作者自己编的名字,无权威)

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
class Date
{
private:
	class A1
	{};
	int a = 1;
	static int b;
public:
	class A2
	{
	private:
		int e = 4;
	public:
		int d = 3;
		void test(const Date& d)
		{
			//cout << a;报错,不能直接访问外部类的非静态成员
			cout << b << endl;//可以直接访问外部类的静态成员
			cout << Date::b << endl;//间接访问也对
			cout << d.b << endl;
				cout << d.a << endl;//可以间接访问外部类的非静态成员
						//内部类是外部类的友元类,可以访问静态成员
		}
	};
	void test(const A2& a)
	{
		//cout << d; 报错,不能直接访问内部类
		cout << a.d << endl;//可以间接访问
		//cout << a.e; 报错,外部类不是内部类的友元
	}
};
int Date::b = 2;
int main()
{
	//A2 a; 报错,内部类受类域限制
	//Date::A1 a1; 报错,内部类受private限制
	Date::A2 a2;
	Date d;
	a2.test(d);
	d.test(a2);
	return 0;
}

5.匿名对象

5.1概念

顾名思义,匿名对象就是没有名字的对象

5.2特性

1.生命周期只在当前语句

2.定义方法:类名(参数);  

注意:这里的参数是传给构造函数的

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
class Date
{
public:
	int _a = 2;
	Date()
	{
		cout << "Date()" << endl;
	}
	Date(int a)
		:_a(a)
	{
		cout << "Date(int a)" << endl;
	}
	~Date()
	{
		cout << "~Date()" << endl;
	}
};
int main()
{
	Date(1);
	cout << "11111111111" << endl;
	Date();
	return 0;
}

 

3.如果不给构造函数传参,括号必须写

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
class Date
{
public:
	int _a = 2;
	Date()
	{
		cout << "Date()" << endl;
	}
	Date(int a)
		:_a(a)
	{
		cout << "Date(int a)" << endl;
	}
	~Date()
	{
		cout << "~Date()" << endl;
	}
};
int main()
{
	Date;//这里虽然没报错,但是对象没有创建
	return 0;
}

相关推荐

  1. lesson03对象(中)续

    2024-04-26 04:24:02       12 阅读
  2. 对象

    2024-04-26 04:24:02       15 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-04-26 04:24:02       14 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-26 04:24:02       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-26 04:24:02       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-26 04:24:02       18 阅读

热门阅读

  1. 关于Gitea 的简单介绍

    2024-04-26 04:24:02       12 阅读
  2. 反序列bit

    2024-04-26 04:24:02       11 阅读
  3. gitlab 16.2.4 恢复

    2024-04-26 04:24:02       12 阅读
  4. “生成元”问题——穷举生成“查找表”

    2024-04-26 04:24:02       36 阅读
  5. C++之const

    2024-04-26 04:24:02       23 阅读
  6. 阿里云直播推流和播流地址的生成方法PHP

    2024-04-26 04:24:02       12 阅读
  7. Unity构建详解(10)——Unity构建流程

    2024-04-26 04:24:02       13 阅读
  8. react之响应事件

    2024-04-26 04:24:02       10 阅读
  9. 377. 组合总和 Ⅳ

    2024-04-26 04:24:02       10 阅读
  10. Spring IOC工作流程

    2024-04-26 04:24:02       10 阅读
  11. ROS——service机制

    2024-04-26 04:24:02       12 阅读