0
点赞
收藏
分享

微信扫一扫

C++类和对象(下)

驚鴻飛雪 2022-03-11 阅读 76
c++

                                     

目录

再谈构造函数

构造函数体赋值

初始化列表

只能在初始化列表初始化的成员及注意事项

explicit

 static成员

概念

面试题:实现一个类,计算中程序中创建出了多少个类对象。

特性 

【问题】

1. 静态成员函数可以调用非静态成员函数吗? 不可以

2. 非静态成员函数可以调用类的静态成员函数吗? 可以

3. 静态成员函数可以调用非静态成员变量吗? 不可以

4. 非静态成员函数可以调用类的静态成员变量吗? 可以

总结 

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

友元

友元函数

友元函数的相关说明:

友元类

1、友元关系是单向的,不具有交换性。

 2、友元关系不能传递

 内部类

概念及特性

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

牛客网一道练习题 

再次理解封装

再次面向对象


再谈构造函数

构造函数体赋值

在之前我们讲构造函数是这样初始化的:

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

那到底怎样在构造函数体内表示才算初始化呢?--->

初始化列表

举个栗子:

class Date
{
public:
	Date(int year, int month, int day)
		:_year(year)
		,_month(month)
		,_day(day)
	{}
private:
	int _year;
	int _month;
	int _day;
};

只能在初始化列表初始化的成员及注意事项

举个栗子:

class A
{
public:
	A(int a) //不传参不能调用该构造函数,不是默认构造函数
		:_a(a)
	{}
private:
	int _a;
};
class B
{
public:
	B(int a, int ref)
		:_a(a)
		, _ref(ref)
		, _n(10)
	{}
private:
	A _a; // 没有默认构造函数
	int& _ref; // 引用
	const int _n; // const
};

3. 尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使用初始化列表初始化。


我们来演示一下:

4. 成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关
我们来通过一个场景演示一下:

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();
}

explicit

举个栗子:

class Date
{
public:
	Date(int year)
		:_year(year)
	{}
private:
	int _year;
	int _month;
	int _day;
};
void TestDate()
{
	Date d1(2018);
	// 用一个整形变量给日期类型对象赋值
	// 实际编译器背后会用2019构造一个临时对象,最后用临时对象给d1对象进行赋值
	d1 = 2019;
}

 static成员

概念

面试题:实现一个类,计算中程序中创建出了多少个类对象。
 

class A
{
public:
	A() 
	{ 
		++_count; 
	}
	A(const A& t) 
	{ 
		++_count;
	}
	static int GetACount()
	{
		return _count; 
	}
private:
	static int _count;
};
int A::_count = 0; //静态成员变量初始化,需要指定类域
void TestA()
{
	cout << A::GetACount() << endl; //调用类里面静态成员函数方法之一
	A a1;
	A a2;
	A a3(a1);
	cout << A::GetACount() << endl;
}
int main()
{
	TestA();
	return 0;
}

运行结果:

特性 

【问题】
1. 静态成员函数可以调用非静态成员函数吗? 不可以

举个栗子:

class Date
{
	Date(int year =1,int month =1,int day=1)
		:_year(year)
		,_month(month)
		,_day(day)
	{}
	void Print()
	{
		cout << _year << " " << _month << " " << _day << endl;
	}
	 static int CountDate()
	{
		 Print();
		_count++;
	}
private:
	int _year;
	int _month;
	int _day;
	static int _count;
};
int Date::_count = 0;
int main()
{
	return 0;
}

运行如下:

2. 非静态成员函数可以调用类的静态成员函数吗? 可以

举个栗子:

class Date
{
public:
	Date(int year =1,int month =1,int day=1)
		:_year(year)
		,_month(month)
		,_day(day)
	{}
	void Print()
	{
		HelloPrint();
		cout << _year << " " << _month << " " << _day << endl;
	}
	 static void HelloPrint()
	{
		 cout << "hello world" << endl;

	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d;
	d.Print();
	return 0;
}

运行结果:

3. 静态成员函数可以调用非静态成员变量吗? 不可以

举个栗子:

class Date
{
public:
	Date(int year =1,int month =1,int day=1)
		:_year(year)
		,_month(month)
		,_day(day)
	{}
	static void Print()
	{
		cout << _year << " " << _month << " " << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d;
	d.Print();
	return 0;
}

运行如下:

4. 非静态成员函数可以调用类的静态成员变量吗? 可以

举个栗子:

class Date
{
public:
	Date(int year =1,int month =1,int day=1)
		:_year(year)
		,_month(month)
		,_day(day)
	{}
	 void Print()
	{
		cout << _count << endl;
		cout << _year << " " << _month << " " << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
	static int _count;
};
int Date::_count = 0;
int main()
{
	Date d;
	d.Print();
	return 0;
}

运行结果:

总结 

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

举个栗子:

class Date
{
public:
	void Print()
	{
		cout << _year << " " << _month << " " << _day;
	}
private:
	//非静态成员变量,可以在成员声明时给缺省值
	int _year = 2022;
	int _month = 3;
	int _day = 3;
};
int main()
{
	Date d;
	d.Print();
	return 0;
}

我们来打印输出一下,看看我们给的缺省值是否给成员变量初始化了:

       如果我们写了拷贝构造(这时候必须写构造函数,具体原因之前讲述过了~),但是又想使用编译器默认生成的构造函数就可以这样来定义:

Date() = default;

友元

友元函数

上面一大段话是什么意思呢?我们用代码演示一下就能明白了:

看下面代码:

class Date
{
public:
	Date(int year, int month, int day)
		: _year(year)
		, _month(month)
		, _day(day)
	{}
	ostream& operator<<(ostream& _cout)
	{
		_cout << _year << "-" << _month << "-" << _day;
		return _cout;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d(2022, 3, 3);
	//cout << d;  正常思维逻辑
	d << cout; //然而定义到类内部只能这样使用
	return 0;
}

        但是我们直接定义到类外面就不能访问类里面的私有成员了,但是也不能把私有成员改成公有,这样会破坏原来的封装性。这时候友元函数就派上用场了:

class Date
{
	friend ostream& operator<<(ostream& _cout,const Date& d);
public:
	Date(int year, int month, int day)
		: _year(year)
		, _month(month)
		, _day(day)
	{}
private:
	int _year;
	int _month;
	int _day;
};
ostream& operator<<(ostream& _cout,const Date& d)//没有了this指针抢位的问题
{
	_cout << d._year << "-" <<d. _month << "-" << d._day;
	return _cout; //这样支持连续输出_cin也是类似
}
int main()
{
	Date d(2022, 3, 3);
	//cout << d;  正常思维逻辑
	cout << d; //然而定义到类内部只能这样使用
	return 0;
}

运行结果:

注意:

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

友元函数的相关说明:

友元类

1、友元关系是单向的,不具有交换性。

举个栗子:

class Date
{
	friend class Time;//Time是Date的友元类,可以访问Date里面的私有成员变量
public:
	Date(int year = 2022, int month = 3, int day = 3)
		: _year(year)
		, _month(month)
		, _day(day)
	{}
private:
	int _year;
	int _month;
	int _day;
};
class Time
{
public:
	void Print(const Date& d)
	{
		cout << d._year << " " << d._month << " " << d._day;
		cout << endl;

		_d._year = 1;
		_d._month = 1;
		_d._day = 1;
		cout << _d._year << " " << _d._month << " " << _d._day; //这种写法不用传参
	}
private:
	int _hour;
	int _minute;
	int _second;
	Date _d;
};
int main()
{
	Date d;
	Time t;
	t.Print(d);
	return 0;
}

运行结果:

 2、友元关系不能传递

举个栗子:

class Time
{
private:
	int _hour = 12;
	int _minute = 12;
	int _second = 12;
};  //为了能够保证Dtae调用到Time,需要Time定义到Date前面,或者声明一下
class Date
{
	friend class Time;
public:
	void Print(const Time& t)
	{
		cout << t._hour << ":" << t._minute << ":" << t._second << endl;
	}
};
int main()
{
	Date d;
	Time t;
	d.Print(t);
	return 0;
}

我们运行一下上面的代码看是否能过:

 内部类

概念及特性

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

class Date
{
public:
	Date(int year = 2022, int month = 3, int day = 3)
		: _year(year)
		, _month(month)
		, _day(day)
	{}
	class Time
	{
	public:
		void Print(const Date& d)
		{
			cout << d._year << " " << d._month << " " << d._day;
		}
	private:
		int _hour;
		int _minute;
		int _second;
	};
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d;
	cout << sizeof(d) << endl;
	Date::Time t;
	cout << sizeof(t) << endl;
	return 0;
}

运行结果如下:

牛客网一道练习题 

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

                        

代码:

class Sum
{
public:
    Sum()
    {
        _ret += _i;
        _i++;
    }
    static int GetN()
    {
        return _ret;
    }
    static void Init()
    {
        _i = 1;
        _ret = 0;
    }
private:
    static int _i;
    static int _ret;
};
int Sum::_i = 1;
int Sum::_ret = 0;
class Solution {
public:
    int Sum_Solution(int n) 
    {
        Sum::Init();
        Sum arr[n];//Sum* p = new Sum[n];
        return Sum::GetN();
    }
};

 我们不用静态成员时:

            

再次理解封装

下面举个例子来让大家更好的理解封装性带来的好处,比如:乘火车出行


我们来看下火车站:
售票系统:负责售票----用户凭票进入,对号入座
工作人员:售票、咨询、安检、保全、卫生等
火车:带用户到目的地

 想想下,如果是没有任何管理的开放性站台呢?火车站没有围墙,站内火车管理调度也是随意,乘车也没有规矩,比如:

再次面向对象

举报

相关推荐

0 条评论