【C++】——类与对象(下)

这篇具有很好参考价值的文章主要介绍了【C++】——类与对象(下)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1. 前言

本文是C++类与对象部分最后一篇文章,类与对象的重点是类与对象(中),本文主要是补充类与对象的剩余知识点及收尾。

2. 再谈构造函数

2.1 构造函数体赋值

在创建对象时,编译器通过调用构造函数,给对象中各个成员变量一个合适的初始值。
构造函数体中的语句只能将其称为赋初值,而不能称作初始化。因为初始化只能初始化一次,而构造函数体内可以多次赋值。

class Date
{
public:

	Date(int year = 1, int month = 1, int day = 1)
	{
		//函数体内初始化
		_year = year;
		_month = month;
		_day = day;
	}

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

2.2 初始化列表

以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括号中的初始值或表达式。
注意
1.每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)
2.类中包含以下成员,必须放在初始化列表位置进行初始化:引用成员变量、const成员变量、自定义类型成员(且该类没有默认构造函数时)
3.自定义类型成员,推荐用初始化列表初始化。
4.初始化列表可以认为是成员变量定义的地方。
5.内置类型也推荐使用初始化列表,但内置类型在函数体内初始化也没问题。

class Time
{
public:
	Time(int hour = 10)
	{
		_hour = hour;
	}

private:
	int _hour;
};

class Date
{
public:
	Date(int year, int month, int day, int& y)
		//成员变量定义
		:_year(year)
		,_month(month)
		,_day(day)
		,_N(20)
		,_x(y)
	{

	}
private:
	//成员变量声明
	int _year;
	int _month;
	int _day;
	Time _t;
	const int _N;//const必须在定义的地方初始化,只有一次机会
	int& _x;
};

int main()
{
	int a = 20;
	//对象定义
	Date a1(2023,5,13,a);

	return 0;
}

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

例如下题:

class A
{
public:
	// 初始化按声明顺序初始化
	A(int a)
		:_a1(a)
		, _a2(_a1)
	{}

	void Print() {
		cout << _a1 << " " << _a2 << endl;
	}
private:
	int _a2;
	int _a1;
};

//A.输出1  1
//B.程序崩溃
//C.编译不通过
//D.输出1  随机值

int main() {
	//D
	A aa1(1);
	aa1.Print();
	return 0;
}

本题正确答案是D选项,因为类中先声明了_a2再声明了_a1,所以初始化列表初始化时,就会先处理a2,而此时a1时随机值,故a2就被初始化成随机值,接下来才把a1初始化为1。

2.3 explicit关键字

构造函数不仅可以构造与初始化对象,对于单个参数或者除第一个参数无默认值其余均有默认值的构造函数,还具有类型转换的作用。用explicit修饰构造函数,将会禁止构造函数的隐式转换。

class Date
{
public:
	//explicit Date(int year)用explicit修饰构造函数,将会禁止构造函数的隐式转换。
	Date(int year)
		:_year(year)
	{
		cout << "Date(int year)" << endl;
	}
	~Date()
	{
		cout << "~Date()" << endl;
	}

private:
	int _year;
};

int main()
{
	Date d1(2022);  // 直接调用构造
	Date d2 = 2022; // 隐式类型转换:构造 + 拷贝构造 + 编译器优化 ->直接调用构造 
	//实际上是先用2022创建一个Date类的临时对象,然后用这个临时对象给d2赋值
	return 0;
}

3. static成员

声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量,用static修饰的成员函数,称之为静态成员函数。
注意
1.静态成员变量一定要在类外进行初始化。
2.静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区
3.静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明
4.类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问
5.静态成员函数没有隐藏的this指针,不能访问任何非静态成员
6.静态成员也是类的成员,受public、protected、private 访问限定符的限制

这里以一道面试题来举例:实现一个类,计算程序中创建出了多少个类对象。

class A
{
public:
	A() 
	{ ++_scount; }
	
	A(const A& t) { ++_scount; }
	
	//静态成员函数 -- 没有this指针
	static int GetCount()
	{
		//_a = 1;
	
		return _scount;
	}
	
private:
	int _a;
	//静态成员变量,属于整个类,生命周期整个程序运行期间,存在静态区
	static int _scount;  //声明
};
	
//类外面定义初始化
int A::_scount = 0;
	
int main()
{
	A a1;
	A a2;
	A a3(a2);

	//cout << a1._scount << endl;
	//cout << a2._scount << endl;
	//cout << A::_scount << endl;

	cout <<A::GetCount() << endl;

	return 0;
}

4. 友元

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

4.1 友元函数

注意
1.友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在类的内部声明,声明时需要加friend关键字。
2.友元函数可访问类的私有和保护成员,但不是类的成员函数。
3.友元函数不能用const修饰。
4.友元函数可以在类定义的任何地方声明,不受类访问限定符限制。
5.一个函数可以是多个类的友元函数。
6.友元函数的调用与普通函数的调用原理相同。

class Date
{
	friend ostream& operator<<(ostream& _cout, const Date& d);
	friend istream& operator>>(istream& _cin, Date& d);
public:
	Date(int year = 1900, int month = 1, int day = 1)
		: _year(year)
		, _month(month)
		, _day(day)
	{}
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& _cin, Date& d)
{
	_cin >> d._year;
	_cin >> d._month;
	_cin >> d._day;
	return _cin;
}

int main()
{
	Date d;
	cin >> d;
	cout << d << endl;
	return 0;
}

4.2 友元类

注意
1.友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。
2.友元关系是单向的,不具有交换性。
比如下面的Time类和Date类,在Time类中声明Date类为其友元类,那么可以在Date类中直接访问Time类的私有成员变量,但想在Time类中访问Date类中私有的成员变量则不行。
3.友元关系不能传递,如果C是B的友元, B是A的友元,不能说明C是A的友元。
4.友元关系不能继承

class Time
{
    friend class Date;   //声明日期类为时间类的友元类,则在日期类中就直接访问Time类中的私有成员变量
public:
    Time(int hour = 0, int minute = 0, int second = 0)
        : _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;
};

5. 内部类

如果一个类定义在另一个类的内部,这个内部的类就叫做内部类。内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去访问内部类的成员。外部类对内部类没有任何优越的访问权限。
内部类就是外部类的友元类,参见友元类的定义,内部类可以通过外部类的对象参数来访问外部类中的所有成员。但是外部类不是内部类的友元。
注意
1.内部类可以定义在外部类的public、protected、private都是可以的。
2.注意内部类可以直接访问外部类中的static成员,不需要外部类的对象 / 类名。
3.sizeof(外部类) = 外部类,和内部类没有任何关系。

class A
{
private:
    static int k;
    int h;
public:
    class B // B天生就是A的友元
    {
    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;
}

6. 拷贝对象时的一些编译器优化

在传参和传返回值的过程中,一般编译器会做一些优化,减少对象的拷贝,这个在一些场景下还是非常有用的。

class W
{
public:
	W(int x = 0)
	{
		cout << "W()" << endl;
	}

	W(const W& w)
	{
		cout << "W(const W& w)" << endl;
	}

	W& operator=(const W& w)
	{
		cout << "W& operator=(const W& w)" << endl;
		return *this;
	}

	~W()
	{
		cout << "~W()" << endl;
	}
};

void f1(W w)
{

}

void f2(const W& w)
{

}

int main()
{
	W w1;
	f1(w1);
	f2(w1);
	cout << endl << endl;

	f1(W()); // 本来构造+拷贝构造--编译器的优化--直接构造
	// 结论:连续一个表达式步骤中,连续构造一般都会优化 -- 合二为一

	W w2 = 1;

	return 0;
}

结论:连续一个表达式步骤中,连续构造一般都会优化——合二为一

7. 结尾

C++类与对象的知识点我们已经通过上中下三篇文章了解的差不多了,类与对象在C++前期的学习中是最重要的知识点,所以我们务必要掌握好。
在类和对象阶段,大家一定要体会到,类是对某一类实体(对象)来进行描述的,描述该对象具有哪些属性,哪些方法,描述完成后就形成了一种新的自定义类型,用该自定义类型就可以实例化具体的对象。
最后,感谢各位大佬的耐心阅读和支持,觉得本篇文章写的不错的朋友可以三连关注支持一波,如果有什么问题或者本文有错误的地方大家可以私信我,也可以在评论区留言讨论,再次感谢各位。文章来源地址https://www.toymoban.com/news/detail-456456.html

到了这里,关于【C++】——类与对象(下)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【C++】类与对象(上)

    之前的文章中讲解了,什么是类、类的实例化,以及封装的意义,若仍有不理解的部分可以移步上一篇文章  【C++】类与对象(引入) 目录 系列文章 1.默认成员函数 2.构造函数 2.1定义 2.2特性 2.2.1重载构造函数 2.2.2与缺省参数混合使用 2.2.3默认构造函数 3.析构函数 3.1定义

    2023年04月15日
    浏览(44)
  • 【C++】——类与对象(上)

    今天我们来学习C++初期最重要的知识点,类与对象,因为类与对象涉及的知识太多,所以我将分为上中下三个部分来为大家讲解类与对象。 C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。 C++是基于面向对象的,关注的是对象,将一

    2024年02月02日
    浏览(41)
  • C++:类与对象

    类是对一组具有共同属性特征和行为特征的对象的抽象,它可将相关数据和这些数据的操作(函数)组合在一起。 类定义格式: 类名 : class是声明类的,类名是标识符,且在其作用域内必须是唯一的。 注:C++规定,标识符以字母(大小写均可,但区分大小写)或下划

    2024年02月12日
    浏览(44)
  • [C++] 类与对象(上)

      目录 1、前言 2、类的引入 3、类的定义 3.1 类的两种定义方式 4、类的访问限定符 5、类的作用域 6、类的实例化 7、类对象模型 7.1 内存对齐规则 7.1 类对象的存储方式 8、this指针 8.1 this指针的特性 8.2 this指针是否可以为空 C语言是 面向过程 的, 关注 的是 过程 ,分析出求解

    2024年02月15日
    浏览(37)
  • C++类与对象(下)

    创建对象时,编译器会调用构造函数给对象中的成员变量一个合适的初始值。 虽然上述构造函数调用时,每个成员变量都有一个初始值了,但是这并不能称为类对象成员的初始化, 构造函数体中的语句只能称为赋初值 ,而不能称为初始化,因为 初始化只能初始一次,而构造

    2024年02月11日
    浏览(39)
  • C++ 类与对象(上)

    目录 本节目标  1.面向过程和面向对象初步认识  2.类的引入  3.类的定义 4.类的访问限定符及封装 4.1 访问限定符 4.2 封装 5. 类的作用域 6. 类的实例化  7.类对象模型 7.1 如何计算类对象的大小 7.2 类对象的存储方式猜测 7.3 结构体内存对齐规则  8.this指针 8.1 this指针的引出

    2024年02月19日
    浏览(42)
  • C++ 类与对象(下)

    目录 1. 再谈构造函数 1.1 构造函数体赋值  1.2 初始化列表  1.3 explicit  2. static成员 2.1 概念 2.2 特性  3.友元 3.1友元函数   3.2 友元类 4. 内部类 5.匿名对象  6.拷贝对象时的一些编译器优化  7. 再次理解类和对象 1. 再谈构造函数 2. Static成员 3. 友元 4. 内部类 5.匿名对象

    2024年02月19日
    浏览(39)
  • 【C++】——类与对象(下)

    本文是C++类与对象部分最后一篇文章,类与对象的重点是类与对象(中),本文主要是补充类与对象的剩余知识点及收尾。 在创建对象时,编译器通过调用构造函数,给对象中各个成员变量一个合适的初始值。 构造函数体中的语句只能将其称为赋初值,而不能称作初始化。

    2024年02月06日
    浏览(32)
  • 【C++】类与对象(中)

    目录 1. 类的6个默认成员函数 2. 构造函数 2.1 概念 2.2 特性 3. 析构函数 3.1 概念 3.2 特性 4. 拷贝构造函数 4.1 概念 4.2 特征 5. 赋值运算符重载 5.1 运算符重载 5.2 赋值运算符重载 5.3 前置++和后置++重载 6. const成员 7. 取地址及const取地址操作符重载 如果一个类中什么成员都没有,

    2024年02月05日
    浏览(46)
  • [C++]类与对象下篇

    目录 类与对象下篇::                             1.再谈构造函数                             2.static成员                             3.友元                             4.内部类                             5.匿名对象                             6.拷贝

    2023年04月25日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包