[c++]——类和对象(下篇)

类和对象——下篇

再谈构造函数
C++11 的成员初始化新玩法。
static成员
友元
内部类

1.再谈构造函数

1.1初始化列表

初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括
号中的初始值或表达式。

  1. 每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)
  2. 类中包含以下成员,必须放在初始化列表位置进行初始化:

引用成员变量
const成员变量
类类型成员(该类没有默认构造函数

class  B
{
public:
	B(int b)//没有默认的构造函数(无参的构造函数)
		:_b(b)
	{
	}
private:
	int _b;
};
class A
{
public:
	A(int a,int b)
		:d(10),
		dday(a),
		n(b)
	{

	}
private:
	const int n;
	int& dday;
	B d;
};
int main()
{
	system("pause");
	return 0;
}

1.2初始化列表的次序

假设将下列代码的_size和_array的顺序交换,择初始化_array数组时开辟空间的大小则会成为随机值

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

class Array
{
public:
	Array(int size = 10)
		:_array((int*)malloc(sizeof(int)*_size))
		,_size(size)		
	{}
private:
	int _size;
	int* _array;	
};
int main()
{
	Array a[10];
	system("pause");
	return 0;
}

1.3 explicit关键字(针对单参数)

匿名对象:(匿名对象的生命周期只有那一行)

1.匿名对象应用
if (N > 10)
		{
			Date tmp(100);
			_aa = tmp;
		}
		_aa = Date(100);
2.		
Date(2019, 3, 6).Display();

注意:此关键字实际上就是为了阻止进行隐式类型转换,在一般的场景下不经常使用
我们来看下面的一个奇特的行为:

    Date a1(10);
	Date a2 = a1;//拷贝构造
	Date a3 = 11;//隐式类型转换1.构造了一个匿名对象 2.拷贝构造给a3 3.优化
	const Date a4 = 11;

加上后则无法通过编译:防止类型转换

explicit Date(int year = 2018, int month = 1, int day = 1)
		:N(10)
	{
		this->_year = year;
		this->_month = month;
		this->_day = day;		
	}

多参数的c++11支持这种情况

Date a3 = {2019,3,2}

2.C++11 的成员初始化新玩法。

非静态成员变量,可以在成员声明时,直接初始化

class B
{
public:
	B(int b)//此处可以不写缺省值,默认构造函数就是无参或者全缺省的构造函数(不需要传参就可以完成初始化的)
		:_b(b)
	{}
	int _b;
};
class A
{
public:
	void Print()
	{
		cout << a << endl;
		cout << b._b << endl;
		cout << p << endl;
	}
private:
	// 非静态成员变量,可以在成员声明时,直接初始化。
	int a = 10;
	B b = 20;
	int* p = (int*)malloc(4);
	static int n;
};
int A::n = 10;
int main()
{
	A a;
	a.Print();

	system("pause");
	return 0;
}

static关键字

声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用static修饰的
成员函数,称之为静态成员函数。静态的成员变量一定要在类外进行初始化

面试题:编写一个函数判断一共创建了多少个类的对象

class A
{
public:
	A()
	{
		++rcount;
	}
	A(const A& d)
	{
		++rcount;
	}
	static int Get()//不加static则会创建一个对象调用函数,加上之后则可以得到准确的结果
	{
		return rcount;
	}
private:
	static int rcount;
};
int A::rcount = 0;
int main()
{
	A a, b;
	A c(a);

	cout << A::Get() << endl;
	system("pause");
	return 0;
}
  1. 静态成员为所有类对象所共享,不属于某个具体的实例(成员共享)
  2. 静态成员变量必须在类外定义,定义时不添加static关键字(定义不加关键字)
  3. 类静态成员即可用类名::静态成员或者对象.静态成员来访问(::访问)
  4. 静态成员函数没有隐藏的this指针,不能访问任何非静态成员(没有this指针不可访问非静态成员)
  5. 静态成员和类的普通成员一样,也有public、protected、private3种访问级别,也可以具有返回值,
    const修饰符等参数(和类普通成员相同)

面试题:求1+2+3+…+n

class Solution {
public:
    class Sum
    {
        public:
        Sum()
        {
            sum+=i;
            i++;
        }
    };
    int Sum_Solution(int n) {
        i = 1;
        sum = 0;
        Sum arr[n];
        return sum;
    }
private:
    static int i;
    static int sum;
};
int Solution::i = 1;
int Solution::sum = 0;

4. 友元

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

友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多
用。

4.1友元函数

友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在类的内部声
明,声明时需要加friend关键字。

若直接重载<<或者>>将不能使用正常顺序书写。

class Date
{
	friend ostream& operator<<(ostream& _cout, const Date& d);
	friend istream& operator>>(istream& _in, Date& d);
public:
	Date(int year, int month, int day)
	{
		this->_year = year;
		this->_month = month;
		this->_day = day;

	}
	void Display()
	{
		cout << this->_month << this->_year << this->_day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
ostream& operator<<(ostream& _cout, const Date& d)
{
	_cout << d._year << "-" << d._month << "-" << d._day;

	return _cout;
}
istream& operator>>(istream& _in, Date& d)
{
	_in >> d._year;
	_in >> d._month;
	_in >> d._day;

	return _in;
}

int main()
{
	Date d(2018, 3, 2);
	cin >> d;
	cout << d;
	system("pause");
	return 0;
}

说明:
友元函数可访问类的私有成员,但不是类的成员函数(不是类成员)
友元函数不能用const修饰(const只能用来修饰this指针)
友元函数可以在类定义的任何地方声明,不受类访问限定符限制(随机定义)
一个函数可以是多个类的友元函数(多指向性)
友元函数的调用与普通函数的调用和原理相同(调用原理相同)

4.2 友元类

友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。
友元关系是单向的,不具有交换性。

比如上述Time类和Date类,在Time类中声明Date类为其友元类,那么可以在Date类中直接访问Time
类的私有成员变量,但想在Time类中访问Date类中私有的成员变量则不行。
友元关系不能传递
如果B是A的友元,C是B的友元,则不能说明C时A的友元。

class Date; // 前置声明
class Time
{
 friend class Date; // 声明日期类为时间类的友元类,则在日期类中就直接访问Time类中的私有成员变
量
public:
 Time(int hour, int minute, int second)
 : _hour(hour)
 , _minute(minute)
 , _second(second)
 {}

private:
 int _hour;
 int _minute;
 int _second;
};


class Date
{
public:
 Date(int year = 1900, int month = 1, int day = 1)
 : _year(year)
 , _month(month)
 , _day(day)
 {}

 void SetTimeOfDate(int hour, int minute, int second)
 {
 // 直接访问时间类私有的成员变量
 _t._hour = hour;
 _t._minute = minute;
 _t.second = second;
 }

private:
 int _year;
 int _month;
 int _day;
 Time _t;
};

内部类

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

class A
{
private:
 static int k;
 int h;
public:
 class B//B类相当于给外部类使用的
 {
 public:
 void foo(const A& a)
 {
 cout << k << endl;//OK
 cout << a.h << endl;//OK
 }
 };
};
int A::k = 1;
int main()
{
 A::B b;
 b.foo(A());

 return 0;
}

A的大小计算与B的大小无关,上面的代码大小为4(静态成员变量不计算大小)

  1. 内部类可以定义在外部类的public、protected、private都是可以的。
  2. 注意内部类可以直接访问外部类中的static、枚举成员,不需要外部类的对象/类名。
  3. sizeof(外部类)=外部类,和内部类没有任何关系。
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值