类与对象_3

构造函数

 首先讨论下什么是构造函数*?
   它是创建对象时,给成员变量赋初始值的一个函数。
 通常情况下我们会这样为变量赋初值:

    //假设一个日期类
	Date(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}

  但这里并不是初始化,因为初始化只能初始化一次,而在类体中可以多次为变量赋值。

初始化列表

实现: :成员变量1(初始值:形参/表达式)
       ,成员变量2(初始值:形参/表达式)
       ...
  注意:

  1. 只有构造函数才有成员变量初始化列表。在初始化期间会为各变量划分空间。
  2. 初始化顺序是根据声明成员变量声明的顺序进行的,与其在初始化列表的顺序无关。
  3. 尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使用初始化列表初始化。

 可以在初始化列表进行初始化也可以在构造函数内进行初始化,那怎么选择?
   类类型成员(该类有非缺省的构造函数),引用类型 和 const类型的变量初始化一定要放在初始化列表中初始化,因为它们都要求在定义
 时就要初始化。

 在有下面这种情况:Date类中创建Time类成员变量时,无法为其赋初始值,这就使得Time类的构造函数为全缺省的构造函数 或者 Date类在其初始化列表的位置显示调用并赋初始值给它。
在这里插入图片描述

类型转换

构造函数除了能够创建对象和初始化对象外,还可以对单参的构造函数进行类型转换。
  在这里插入图片描述

 这段代码执行时会报错,在这里"d = 1997"会进行隐式转换。
   
在这里插入图片描述
因为单参构造函数,全缺省构造函数都可以被调用所以系统不知道调用那个,就会报错。
 解决上述问题的方式,就是在单参构造函数声明前加"explicit"
  关键字: explicit
   作用:禁止单参的构造函数类型隐式转化。

静态成员

 在c++类中声明成员时可以加上static关键字,这样声明的成员就叫做静态成员。
特性:

  1. 静态成员变量必须在类外进行显式初始化,定义时不添加static关键字;
class Date{	
public:
	Date(int year = 2018, int month = 10, int day = 12)
		:_month(month)
		,_day(day)
	{}
private:	
	static int _year;	   // 声明 "_year" 为静态变量
	int _month;
	int _day;
};
int Date::_year = 2018;   // 类外初始化静态变量
  1. 静态成员为所有类对象所共享,即使没有对象创建,类的静态数据成员也存在;
  2. 从外部访问类的静态成员通过"类名 :: 静态成员",“对象 . 静态成员” 或者 指针 来访问;
int main()
{
	cout << Date::PrintYear() << endl;  // 类名直接访问
	Date d1;
	Date* d2;
	int tmp = d1.PrintYear();   // 对象.引用的方式
	int tmp2 = d2->PrintYear(); // 指针方式

	return 0;
}
  1. 静态成员函数没有隐藏的this指针,不能直接访问任何非静态成员,但是可以通过对象名间接的访问;
class Date{

public:
	Date(int year = 2018, int month = 10, int day = 12)
		:_month(month)
		,_day(day)
	{}

	static void Print(const Date &d)  // 通过引用已创建好的对象来访问其他非静态成员变量
	{
		int year = _year;
		//int month = _month; // 由于静态函数没有this指针,
		//int day = _day;     // 就无法直接访问非静态成员变量
		int month = d._month;
		int day = d._day;
		cout << year << "-" << month << "-" << day << endl;
	}

private:
	static int _year;
	int _month;
	int _day;
};

int Date::_year = 2018;

int main()
{
	Date d1;
	Date::Print(d1);

	return 0;
}
  1. 静态成员和类的普通成员一样,也有public、protected、private3种访问级别,也可以具有返回值,const修饰符等参数;
  2. 由于静态成员是在静态存储区,而不是堆栈区创建的,所以静态成员变量在对象中不占内存。

友元

 友元函数 & 友元类
  优缺点:友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多用。
 友元函数
   假如我们重载输出操作符"<<",如果放在类内当作一个成员函数,由于类的成员函数第一个参数一定是隐含的this指针,所以我们调用方式一定是使用Date类的对象(this指针),然而这样的输出语句不符合我们习惯常用的。为此我们就需要在类外定义一个具有全局属性的operator函数,但这样又没办法使用类中的私有成员变量,此时就可以借助友元函数的方式解决。

  用法: 友元函数可以在类内任何位置声明(别在定义成员变量那就行),并且要在声明前加 “friend”,它的定义放在类外与普通函数方式一样。
     这样友元函数就可以直接访问类的私有成员变量。
 总结

  1. 友元函数可访问类的私有成员,但不是类的成员函数; // 子类也就不能继承基类的友元函数
  2. 友元函数不能用const修饰 ;   // 因为声明中const修饰的是实际是this指针,而友元函数不属于类函数,所以没有this指针,也就不能被const修饰
  3. 友元函数可以在类定义的任何地方声明不受类访问限定符限制
  4. 一个函数可以是多个类的友元函数;
  5. 友元函数的调用与普通函数的调用原理相同;
  6. 友元关系是单向的,不具有交换性,不能传递;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1.声明一个动物基Animal,私有整型成员变量年龄age,请定义一个派生Dog,在其成员函数SetAge(int n)中直接给age赋值,测试下看是否会出问题?如何解决? 2.设计一个单基继承的层次程序,用Person派生出Student,增加属性学号index和年级level。Person中至少有姓名name、年龄age等数据成员,以及构造函数、输出函数等,其余成员函数根据需要添加。在主函数中进行测试。 3.定义一个学生Student和教师Teacher,学生有姓名name、学号index等数据成员,教师有姓名name、工作证号workID、职称title、课程course、周学时hoursPerWeek等数据成员。再定义一个助教TeachingAssistant,多继承于学生和教师,该可以使用学生的全部数据成员,以及教师的课程和周学时数据成员。要求:每个提供自定义的构造函数和析构函数,并通过同名函数ShowInfo来显示全部数据成员的值。在主函数中进行测试。 4.声明一个Person,包含姓名name和年龄age等私有数据成员以及相关的成员函数;由它派生出领导Leader,包含职务position和部门department私有数据成员以及相关的成员函数;再由Person派生出工程师Engineer,包含职务position和专业speciality私有数据成员以及相关的成员函数;再由Leader和Engineer派生出主任工程师Chairman。在主函数中测试各对象初始化和信息输出,查看是否会出问题?如何解决?

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值