类和对象 - 下(C++)

本文详细阐述了C++中的构造函数、初始化列表的作用和规则,强调了初始化列表的重要性,特别是对于引用、const成员和无默认构造函数的自定义类型。同时,讨论了explicit关键字防止隐式类型转换的情况。接着介绍了静态成员的概念和特性,包括静态成员函数和变量的使用。此外,讲解了友元的原理和分类,如友元函数和友元类,以及内部类的特性。最后提到了匿名对象和编译器对拷贝对象的优化策略。
摘要由CSDN通过智能技术生成

目录

构造函数补充

构造函数体赋值

初始化列表

explicit关键字

Static成员

概念

特性

友元

友元函数

友元类

内部类

匿名对象

编译器对拷贝对象的优化

理解类和对象


构造函数补充

构造函数体赋值

构造函数:

我们知道 构造函数本质就是在对象创建的同时对其进行初始化操作!

在创建对象时,编译器通过调用构造函数,给对象中各个成员变量一个合适的初值!


代码:

#include <stdio.h>
using namespace std;

//日期类
class Date
{
public:
	//构造函数
	Date(int year = 0, int month = 0, int day = 0)
	{
		_year = year;
		_month = month;
		_day = day;
	}

private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1(2023, 5, 17);
	return 0;
}

虽然上述构造函数调用后,对象已经有了一个初始值,但是该初始值不能称之为对象中成员变量的初始化,而是赋值,在构造函数体中的语句,就是进行赋值操作,而不是初始化,因为初始化只能初始化一次,而构造函数体内可以多次赋值。而定义并初始化的部分是在构造函数初始化列表部分来完成的!


初始化列表

初始化列表:

初始化列表是构造函数的一部分,我们知道在类中书写的成员变量是声明,只有在对象实例化的时候才会定义开空间,而对象在实例化的时候是调用构造函数的,所以可以认为初始化列表是成员变量定义的位置!


写法:

构造函数下面紧接着写:以一个冒号开始,接着是一个以逗号隔开的数据成员列表,每个成员变量后面跟一个放在括号中的初始值或表达式!


代码:

#include <stdio.h>
using namespace std;

//日期类
class Date
{
public:

	//构造函数
	Date(int year = 0, int month = 0, int day = 0)
		:_year(year),
		_month(month),
		_day(day)
	{}

private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1(2023, 5, 17);
	return 0;
}

注意:

1、每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)

2、类中包含以下成员,必须放在初始化列表位置进行初始化:

        1>引用成员变量

        2>const成员变量

        3>自定义类型(且该类没有默认构造函数时)


代码:

//因为引用在定义的时候必须要初始化
//const修饰的成员是不能被改变的,只能在初始化的时候给值
//而对于自定义的类型,会去调用它的默认构造函数
//若没有默认构造,就得需要将其写入初始化列表进行初始化

#include <iostream>
using namespace std;

class Basu
{
public:
	Basu(int a)
		:_a(a)
	{}
private:
	int _a;
};

class Definitely
{
public:
	Definitely(int a, int ref)
		:_aobj(a)
		, _ref(ref)
		, _n(10)
	{}
private:
	Basu _aobj;  // 没有默认构造函数的类
	int& _ref;  // 引用 成员
	const int _n; // const 成员
};

int main()
{
	return 0;
}

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


代码:

//不管是否使用初始化列表初始化
//对于自定义类型都会去走初始化列表进行初始化
//对于自定义类型会默认去调用它的默认构造
//不管是否书写在初始化列表初始化
//都会去走初始化列表

#include <iostream>
using namespace std;

class Time
{
public:
    Time(int hour = 0)
        :_hour(hour)
    {
        cout << "Time()" << endl;
    }
private:
        int _hour;
};

class Date
{
public:
    Date(int day)
    {}
private:
    int _day;
    Time _t;
};

int main()
{
    Date d(1);
}

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


代码:

//初始化列表中是按照类中声明的顺序进行初始化的
#include <iostream>
using namespace std;

//该类中是先声明a2,再定义a1
//初始化列表在初始化的时候先初始化a2,再初始化a1
//先初始化a2 a2是用a1初始化的,因为a1没有初始化,a1的值是随机值
//所以a2的值是一个随机值
//再用 a初始化a1 ,a我们传值为1,所以a1的结果为1
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();
}

总结:

初始化列表是成员变量定义的地方,对于类中的成员变量,我们在初始化列表位置不管是否显示写,默认都要走初始化列表,但对于三种情况必须要在初始化列表显式书写,(1、引用成员。2、const修饰的成员,3、没有默认构造函数的自定义类型!)原因:引用在定义的时候必须初始化。const成员定义的时候需要给值,因为只能在定义的时候初始化一次,后续就不能改变了,所以必须走初始化列表。对于没有默认构造函数的自定义类型而言,我们知道构造函数对于自定义类型会去调用它的默认构造,若是没有默认构造,该自定义类型就无法完成初始化操作,此时就需要我们去处初始化列表指定调用它的初始化函数,或者对它进行初始化!


代码:

//默认构造函数分为三种:
// 1、全缺省的默认构造函数
// 2、无参的默认构造函数
// 3、不写编译器默认生成的默认构造函数(编译器默认生成的是一个无参的构造函数)

// 初始化列表是成员定义的地方
// 引用成员必须显式写在初始化列表中
// const 成员必须显式写在初始化列表中
// 无默认构造的自定义类型成员,也必须显式写在初始化列表中

#include <iostream>
using namespace std;

//时间类
class Time
{
public:

	//构造函数(非默认构造函数)
	Time(int hours,int minutes,int second)
		:_hours(hours),
		_minutes(minutes),
		_seconds(second)
	{}

	//打印
	void Print()
	{
		cout << _hours << " : " << _minutes << " : " << _seconds << endl;
	}

private:
	int _hours;
	int _minutes;
	int _seconds;
};

//日期类
class Date
{
public:
	//默认构造函数
	Date(int year = 0, int month = 0, int day = 0,int a=20)
		:_year(year),
		_month(month),
		_day(day),
		_t(16,22,36),//无默认构造的自定义类型
		_a(a),//引用成员
		_b(20)//const成员
	{}

	//打印
	void Print()
	{
		cout << _year << " - " << _month << " - " << _day <<"  ";
		_t.Print();
	}

private:
	int _year;
	int _month;
	int _day;
	Time _t;//自定义类型

	int& _a;//引用成员
	const int _b;//const 成员
};

int main()
{
	Date d1(2023, 5, 17);
	d1.Print();

	return 0;
}

explicit关键字

类型转换:

对于构造函数不仅可以构造和初始化对象,还对于,只有一个参数或者第一个参数没有默认值,其余参数都有默认值的构造函数,具有隐式类型转换的作用!

 

例如:

#include <iostream>
using namespace std;

class Date
{
public:
		//单参构造函数,没有使用explicit修饰,具有类型转换作用
	    Date(int year)
		:_year(year)
		{}

	Date& operator=(const Date& d)
	{
		if (this != &d)
		{
			_year = d._year;
			_month = d._month;
			_day = d._day;
		}
		return *this;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1(2022);
	// 用一个整形变量给日期类型对象赋值
	// 实际编译器背后会用2023构造一个无名对象,最后用无名对象给d1对象进行赋值
	//有隐式转换,而无名对象是临时生成的对象,具有常属性!
	d1 = 2023;
	return 0;
}

#include <iostream>
using namespace std;
class Date
{
public:
	/*
	虽然有多个参数,但是创建对象时后两个参数可以不传递,
	没有使用explicit修饰,具有类型转换作用*/
	Date(int year, int month = 1, int day = 1)
		: _year(year)
		, _month(month)
		, _day(day)
	{}

	Date& operator=(const Date& d)
	{
		if (this != &d)
		{
			_year = d._year;
			_month = d._month;
			_day = d._day;
		}
		return *this;
	}
private:
	int _year;
	int _month;
	int _day;
};
void Test()
{
	Date d1(2022);
	// 用一个整形变量给日期类型对象赋值
	// 实际编译器背后会用2023构造一个无名对象,最后用无名对象给d1对象进行赋值
	d1 = 2023;
}

int main()
{
	Test();
	return 0;
}

隐式类型转换:

隐式类型转换会生成一个临时对象,而临时对象具有常属性!


总:

上述两份代码 分别是单参构造和第一个参数没有默认值的构造函数,当构造函数是上述两者的时候,对于对象进行操作是具有隐式类型转换作用的!


解决方案:

若不想让其具有隐式类型转换,则只需要将两种构造函数用explicit 关键字修饰即可!


代码:

#include <iostream>
using namespace std;

class Date
{
public:
		// 1. 单参构造函数,没有使用explicit修饰,具有类型转换作用
		// explicit修饰构造函数,禁止类型转换
	explicit Date(int year)
	:_year(year)
	{}

	/*
	2. 虽然有多个参数,但是创建对象时后两个参数可以不传递,
	没有使用explicit修饰,具有类型转换作用

	explicit修饰构造函数,禁止类型转换
	explicit Date(int year, int month = 1, int day = 1)
	: _year(year)
	, _month(month)
	, _day(day)
	{}
	*/
	Date& operator=(const Date& d)
	{
		if (this != &d)
		{
			_year = d._year;
			_month = d._month;
			_day = d._day;
		}
		return *this;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1(2022);
	// 用一个整形变量给日期类型对象赋值
	// 实际编译器背后会用2023构造一个无名对象,最后用无名对象给d1对象进行赋值
	d1 = 2023;
// 因为explicit修饰构造函数,禁止了单参构造函数类型转换所以会报错

	return 0;
}

总结:

单参以及第一个参数没有缺省值的构造函数,在对象操作时会产生隐式类型转换,也就是产生临时对象,临时对象具有常性,而在新的编译器下会优化一些操作,比如会将一行中的构造+拷贝构造优化成构造……等!若不想让其发生隐式类型转换,用explicit来修饰单参或者第一个参数无缺省值的构造函数即可!修饰之后若有隐式转换的场景编译器会报错!


Static成员

概念

概念:

在类中用static修饰的成员,称为类的静态成员,,用static修饰的成员变量,称为静态成员变量。用static修饰的成员函数,称为静态成员函数。(注:静态成员变量一定在类外面进行初始化)


代码:

#include <iostream>
using namespace std;

class Date
{
public:
	//构造
	Date(int year = 0, int month = 0, int day = 0)
		:_year(year),
		_month(month),
		_day(day)
	{}

	//静态成员函数(不存在对象中,是在静态区中)
	static int GetMonthDay(int year,int month)
	{
		int MonDay[13] = { 0,31,29,31,30,31,30,31,31,30,31,30,31 };
		if ((month == 2) && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
		{
			return 29;
		}

		return MonDay[month];
	}

private:
	int _year;
	int _month;
	int _day;
	static int _a;//static成员静态成员
	//是不走初始化列表
	//需要在类外面定义
};
//在类外面定义
int Date::_a = 10;

int main()
{
	Date d1;
	return 0;
}

特性

静态成员的特性:

1、静态成员函数为所有类对象共享,不属于某个具体的对象,存在静态区

2、静态成员变量必须在类外面定义,定义时无需添加static关键字,但要指定类域,类中只是声明。

3、静态成员可以用(类名::静态成员)或者(对象.静态成员)来访问

4、静态成员函数没有隐藏的this指针

5、静态成员也是类的成员,也受类访问限定符的限制(public、private、protected)!


代码:

//1、静态成员函数为所有类对象共享,不属于某个具体的对象,存在静态区
//2、静态成员变量必须在类外面定义,定义时无需添加static关键字,但要指定类域,类中只是声明。
//3、静态成员可以用(类名::静态成员)或者(对象.静态成员)来访问
//4、静态成员函数没有隐藏的this指针
//5、静态成员也是类的成员,也受类访问限定符的限制(public、private、protected)!
#include <iostream>
using namespace std;

class Date
{
public:
	//构造函数
	Date(int year = 0, int month = 0, int day = 0)
		:_year(year),
		_month(month),
		_day(day)
	{}

	//静态成员函数
	//静态成员函数没有this指针
	static int GetMonthDay(int year, int month)
	{
		int Day[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
		if ((month == 2) && ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0))
		{
			return 29;
		}
		return Day[month];
	}


private:
	int _year;
	int _month;
	int _day;
	static int _a;//静态成员变量
};

//静态成员变量必须在类外面定义,
//定义时无需添加static关键字,但要指定类域,类中只是声明。
int Date::_a = 20;

//静态成员函数为所有类对象共享,不属于某个具体的对象,存在静态区
int main()
{
	//静态成员可以用(类名::静态成员)来访问

	//cout << Date::_a << endl;//无法访问静态成员变量_a
	//因为静态成员是受类访问限定符的限制的

	int day = Date::GetMonthDay(2023, 5);
	cout << day << endl;
	

	//(对象.静态成员)来访问
	Date d1;
	int dayy = d1.GetMonthDay(2024, 5);
	cout << dayy << endl;

	return 0;
}

友元

友元关键字: firend


概念:

类的友元,突破了类的封装性,可在类外面访问类的私有或保护成员,类的友元需要在类中声明,声明时用friend修饰!


简述:

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


分类:

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


友元函数

问题:

当我们在日期类中去重载operator<<,发现没办法将 operator<< 重载为成员函数,因为cout输出流对象将对象的this指针位置抢了,本来对象是要传递给隐含的this指针的,但是由于在书写的时候cout要写在前面,导致cout传给了this指针,而对象传给了另一个参数,这样结果就紊乱了。所以要将operator<<重载成全局函数,,而重载成全局函数,之后,没法通过该函数去访问类的成员,此时就需要友元来修饰该函数,来解决问题!


代码:

//重载 << 运算符要重载到全局位置
//重载到类中会发生this指针传递问题

#include <iostream>
using namespace std;

class Date
{
public:
	//构造
	Date(int year=0,int month=0,int day=0)
		:_year(year),
		_month(month),
		_day(day)
	{}

	重载 << 运算符
	 若重载到类中会发生this指针传递问题
	 d1 << cout; -> d1.operator<<(&d1, cout); 不符合常规调用
 //   // 因为成员函数第一个参数一定是隐藏的this,所以d1必须放在<<的左侧

	//ostream& operator<<(ostream& out)
	//{
	//	out << _year << "年" << _month << "月" << _day << "日";
	//}


	//为了在类外面访问类中的成员用友元来修饰该函数
	//全局函数声明的时候需要加上friend修饰
	//说明该函数是该类的友元
	//可以通过该全局函数,访问类的私有或保护成员!
	friend ostream& operator<<(ostream& out, const Date& d);

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

//重载到全局位置
ostream& operator<<(ostream& out, const Date& d)
{
	out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
	return out;
}

int main()
{
	Date d1(2023, 5, 21);
	cout << d1;

	return 0;
}

注意:

1、友元函数可以访问类的私有成员和保护成员,但其不是类的成员函数

2、友元函数不能用const修饰,因为没有this指针

3、友元函数可以在类中任何地方声明,不受类访问限定符的限制

4、一个函数可以是多个类的友元函数

5、友元函数的调用和普通函数的调用原理相同


代码:

#include <iostream>
using namespace std;

//1、友元函数可以访问类的私有成员和保护成员,但其不是类的成员函数
//2、友元函数不能用const修饰
//3、友元函数可以在类中任何地方声明,不受类访问限定符的限制
//4、一个函数可以是多个类的友元函数
//5、友元函数的调用和普通函数的调用原理相同

class Date1
{
public:
	Date1(int year=0,int month=0,int day=0)
		:_year(year),
		_month(month),
		_day(day)
	{}

	//打印函数
	friend void Print(int year, int month, int day);

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

class Date
{
public:
	//构造函数
	Date(int year=0,int month=0,int day=0)
		:_year(year),
		_month(month),
		_day(day)
	{}

	//友元函数可以在类中任何地方声明,不受类访问限定符的限制
	//打印函数
	friend void Print(int year, int month, int day);

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

//友元函数不能用const修饰
//const修饰的是this指针,而友元函数是全局函数
//没有this指针所以不能用const修饰

//一个函数可以是多个类的友元函数
//打印函数
void Print(int year,int month,int day)
{
	cout <<year << "-" << month << "-" << day << endl;
}

int main()
{
	//友元函数的调用和普通函数的调用原理相同
	Date d1(2023, 5, 22);
	Print(2023, 5, 22);
	return 0;
}

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


友元类

概念:

友元类的所有成员函数都可以是另一个类的友元函数,都可以访问一个类中的非公有成员。


注意:

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

        例如下述代码 Date 类  和  Time类,在Time类中声明Date类为其友元,

        那么可以在Date类中直接访问Time类的私有成员,

        但想在Time类中访问Date类中的私有成员是不被允许的!

2、友元关系不能传递

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

3、友元关系是不能继承的(后续文章会写继承)


代码:

#include <iostream>
using namespace std;

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 = 2000, int month = 1, int day = 1)
        : _year(year)
        , _month(month)
        , _day(day)
    {}

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

    void Print()
    {
        cout << _year << "-" << _month << "-" << _day<<"  ";
        cout << _t._hour << ":" << _t._minute << ":" << _t._second << endl;
    }

private:
    int _year;
    int _month;
    int _day;

    Time _t;
};

int main()
{
    Date d1(2023, 5, 22);
    d1.SelectTime(9,37,52);
    d1.Print();
    return 0;
}

总结:

友元类不具有传递性、友元关系不具有交换性、友元关系不能继承!


内部类

概念:

如果一个类定义在另一个类的内部,这个类就是内部类。

内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去访问内部类的成员。外部类对内部类没有任何优越的访问权限!


代码:

#include <iostream>
using namespace std;

class Time
{
public:
	//构造
	Time(int hours=0,int minutes=0,int seconds=0)
		:_hours(hours),
		_minutes(minutes),
		_seconds(seconds)
	{}

	//内部类
	class Date
	{
	public:
		//构造
		Date(int year=0,int month=0,int day=0)
			:_year(year),
			_month(month),
			_day(day)
		{}

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

private:
	int _hours;
	int _minutes;
	int _seconds;

};

int main()
{
	Time t1(9, 53, 46);
	//不能通过外部类对象去访问内部类成员
	//cout << t1._year << endl;

	return 0;
}

注意:

内部类天生就是外部类的友元类,内部类可以通过外部类的对象参数来访问外部类中的所有成员,但外部类不是内部类的友元。不能通过外部类访问内部类成员!


特性:

1. 内部类可以定义在外部类的public、protected、private都是可以的。

2. 注意内部类可以直接访问外部类中的static成员,不需要外部类的对象或类名。

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

4. 用内部类实例化对象,不能直接使用内部类去实例化,需要在类名前面指定外部类 类域


代码:

#include <iostream>
using std::cout;
using std::endl;

class A
{
private:
    static int k;
    int h;
public:
    class B // B天生就是A的友元
    {
    public:
        void foo(const A& a)
        {
            //访问外部类的static成员
            cout << k << endl;//OK
            cout << a.h << endl;//OK
        }
    };
};

int A::k = 1;

int main()
{
    //通过类域指定用创建内部类对象
    A::B b;
    b.foo(A());

    //sizeof(外部类) 与内部类无关,不包含内部类!
    cout << sizeof(A) << endl;

    return 0;
}

总结:

内部类天生就是外部类的友元,不能通过外部类访问内部类的成员,内部类可以定义在外部类内任意位置,sizeof(外部类) 跟内部类没有任何关系,且内部类可以直接访问外部类的静态成员。在定义内部类对象时,需要用外部类进行域作用限定符指定!


匿名对象

概念:
在C++中存在一种没有名字的对象,该对象被称之为匿名对象。匿名对象是直接用类去创建。匿名对象的特性是:即用即销毁!


特点:

匿名对象即用即销毁,在当前行定义,当前行结束就销毁了。


代码:

#include <iostream>
using namespace std;

class Date
{
public:
	//默认构造
	Date(int year=0,int month=0,int day=0)
		:_year(year),
		_month(month),
		_day(day)
	{
		cout << "Date(int year=0,int month=0,int day=0)" << endl;
	}

	//析构
	~Date()
	{
		cout<<"~Date()"<< endl;
	}

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

int main()
{
	//有名对象
	Date d1(2023, 5, 22);

	//匿名对象
	//即用即销毁,只在当前行有效
	Date(2023, 5, 5);
	Date();

	return 0;
}

注意:

1、匿名对象在创建的同时调用类的成员!

2、用const 引用匿名对象,延长了匿名对象的生命周期!

        匿名对象实际上是通过默认构造创建出一个临时对象,而临时对象具有常性,

        用const引用是可行的!


代码:

#include <iostream>
using namespace std;

class Date
{
public:
	//默认构造
	Date(int year = 0, int month = 0, int day = 0)
		:_year(year),
		_month(month),
		_day(day)
	{
		//cout << "Date(int year=0,int month=0,int day=0)" << endl;
	}

	void Print()const
	{
		cout << _year << "年" << _month << "月" << _day << "日" << endl;
	}

	//析构
	~Date()
	{
		//cout << "~Date()" << endl;
	}

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

int main()
{
	//创建的同时调用成员
	Date(2023, 5, 22).Print();

	//用const引用之后当前行结束匿名对象并没有销毁
	// 可认为const延长了匿名对象的生命周期
	//用const引用匿名对象
	const Date& d1 = Date();
	d1.Print();

	return 0;
}

总结:

匿名对象即用即销毁,用const引用延长了匿名对象的生命周期,可在定义的同时通过匿名对象调用类的成员!


编译器对拷贝对象的优化

概念:

对象在传参或传返回值的过程中,都有可能会形成多种拷贝,一般新的C++编译器都会对其进行优化处理,减少对象拷贝次数,以提高效率!


#include <iostream>
using namespace std;

class A
{
public:
	//默认构造
	A(int a = 0)
		:_a(a)
	{
		cout << "A(int a)" << endl;
	}

	//拷贝构造
	A(const A& aa)
		:_a(aa._a)
	{
		cout << "A(const A& aa)" << endl;
	}

	//赋值运算符重载
	A& operator=(const A& aa)
	{
		cout << "A& operator=(const A& aa)" << endl;
		if (this != &aa)
		{
			_a = aa._a;
		}
		return *this;
	}

	//析构函数
	~A()
	{
		cout << "~A()" << endl;
	}

private:
	int _a;

};

void f1(A aa)
{}

A f2()
{
	A aa;
	return aa;
}

int main()
{
	// 传值传参
	A aa1;
	f1(aa1);//会进行拷贝构造
	cout << endl;

	// 传值返回
	f2();
	cout << endl;

	// 隐式类型,连续构造+拷贝构造->优化为直接构造
	f1(1);

	// 一个表达式中,连续构造+拷贝构造->优化为一个构造
	f1(A(2));
	cout << endl;

	// 一个表达式中,连续拷贝构造+拷贝构造->优化一个拷贝构造
	A aa2 = f2();
	cout << endl;

	// 一个表达式中,连续拷贝构造+赋值重载->无法优化
	aa1 = f2();
	cout << endl;

	return 0;
}

理解类和对象

现实生活中的实体计算机并不认识,计算机只认识二进制格式的数据。如果想要让计算机认识现 实生活中的实体,用户必须通过某种面向对象的语言,对实体进行描述,然后通过编写程序,创 建对象后计算机才可以认识。


比如想要让计算机认识洗衣机,就需要:

1. 用户先要对现实中洗衣机实体进行抽象---即在人为思想层面对洗衣机进行认识,洗衣机有什 么属性,有那些功能,即对洗衣机进行抽象认知的一个过程

2. 经过1之后,在人的头脑中已经对洗衣机有了一个清醒的认识,只不过此时计算机还不清 楚,想要让计算机识别人想象中的洗衣机,就需要人通过某种面相对象的语言(比如:C++、 Java、Python等)将洗衣机用类来进行描述,并输入到计算机中

3. 经过2之后,在计算机中就有了一个洗衣机类,但是洗衣机类只是站在计算机的角度对洗衣 机对象进行描述的,通过洗衣机类,可以实例化出一个个具体的洗衣机对象,此时计算机才 能理解洗衣机是什么东西。

4. 用户就可以借助计算机中洗衣机对象,来模拟现实中的洗衣机实体了。


 

类是对某一类实体(对象)来进行描述的,描述该对象具有那 些属性,那些方法,描述完成后就形成了一种新的自定义类型,才用该自定义类型就可以实例化 具体的对象。

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值