类和对象 - 下(C++)

news2024/11/19 11:25:48

目录

构造函数补充

构造函数体赋值

初始化列表

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. 用户就可以借助计算机中洗衣机对象,来模拟现实中的洗衣机实体了。


 

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/554157.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Android】配置不同的开发和生产环境

目录 前言 配置build.gradle&#xff08;Module级别&#xff09; 创建对应环境的目录 切换不同环境 ​编辑选择打包的环境 前言 在web开发中不同的环境对应的配置不一样&#xff0c;比如开发环境的url是这样&#xff0c;测试环境的url是那样的&#xff0c;在app中也会涉…

双轮平衡车实现自平衡功能

1. 功能说明 在双轮小车上安装一个六轴陀螺仪传感器&#xff0c;本文示例将实现双轮小车自主平衡功能。 2. 电子硬件 在这个示例中&#xff0c;我们采用了以下硬件&#xff0c;请大家参考&#xff1a; 主控板 Basra主控板&#xff08;兼容Arduino Uno&#xff09; 扩展板 Big…

基于网络的思维导图WiseMapping

在退烧了一天半之后&#xff0c;老苏的抗原终于变两道杠了。之前还总怀疑自己是无症状&#xff0c;大意了&#xff0c;被新冠给查缺补漏了 &#x1f602; 什么是 WiseMapping &#xff1f; WiseMapping 是一款基于网络的免费思维导图产品。该项目的目标是提供可由企业、教育和学…

Java面试知识点(全)-分布式和微服务-dubbo面试知识点

Dubbo是什么&#xff1f; Dubbo是阿里巴巴开源的基于 Java 的高性能 RPC 分布式服务框架&#xff0c;现已成为 Apache 基金会孵化项目。 面试官问你如果这个都不清楚&#xff0c;那下面的就没必要问了。 官网&#xff1a;http://dubbo.apache.org 为什么要用Dubbo&#xff1f…

内存泄漏之DispatcherTimer

https://www.jianshu.com/p/7e9ecb383bd0 我们经常会在程序中使用DispatcherTimer&#xff0c;但是如果一不小心就会发生内存泄漏&#xff0c;请看下面的Demo&#xff1a; 内存泄漏代码 我创建了一个简单的窗口Example1.xaml&#xff1a; <Window x:Class"MemoryLea…

Keep your Eyes on the Lane Real-time Attention-guided Lane Detection 论文精读

关注车道&#xff1a;实时注意力引导车道线检测 摘要 现代车道线检测方法在复杂的现实世界场景中取得了显著的性能&#xff0c;但许多方法在保持实时效率方面存在问题&#xff0c;这对自动驾驶汽车很重要。在这项工作中&#xff0c;我们提出了LaneATT&#xff1a;一种基于锚点…

【降维打击】T分布随机近邻嵌入(T-SNE)Python实践

近几天看到论文里面有T分布随机近邻嵌入&#xff08;T-distributed stochastic neighbor embedding, T-SNE&#xff09;这种可视化方法&#xff0c;以前好像也看到过&#xff0c;但没有系统了解过&#xff0c;现有时间正好实践记录一下。 1. T-SNE简介 T-SNE是一种降维方法&am…

搭建监控日志系统

在微服务或者集群架构中&#xff0c;一次请求的调用会跨多个服务&#xff08;web&#xff0c;mysql&#xff0c;feign等&#xff09;、多个模块&#xff08;用户模块&#xff0c;商品模块等&#xff09;、多个容器&#xff08;用户模块可能有多个实例&#xff09;&#xff0c;这…

【科普】干货!带你从0了解移动机器人(二)—— 移动机器人硬件组成

移动机器人是一个多功能于一体的综合系统&#xff0c;内容涵盖了传感器技术、自动化技术、信息处理、电子工程等&#xff0c;它集环境感知、动态决策与规划于一体&#xff0c;是目前科学技术发展最活跃的领域之一。移动机器人的各种组件之间需要协同工作才能实现机器人的自主移…

【源码解析】RuoYi-Vue-Plus翻译功能 Translation 源码分析

类说明功能Translation通用翻译注解标注需要翻译的字段&#xff0c;用于实体类字段上TranslationType翻译类型注解标注翻译字段的实现类型&#xff0c;用于实现类上标注TransConstant翻译常量TranslationType 类型常量TranslationConfig翻译模块配置类配置初始化&#xff0c;设…

深度学习基础入门篇[9.2]:卷积之1*1 卷积(残差网络)、2D/3D卷积、转置卷积数学推导、应用实例

【深度学习入门到进阶】必看系列&#xff0c;含激活函数、优化策略、损失函数、模型调优、归一化算法、卷积模型、序列模型、预训练模型、对抗神经网络等 专栏详细介绍&#xff1a;【深度学习入门到进阶】必看系列&#xff0c;含激活函数、优化策略、损失函数、模型调优、归一化…

一文了解customRef 自定义ref使用

概念 按照文档中的说明&#xff1a;customRef 可以用来创建一个自定义的 ref&#xff0c;并对其依赖项跟踪和更新触发进行显式控制。它需要一个工厂函数&#xff0c;该函数接收 track 和trigger函数作为参数&#xff0c;并且应该返回一个带有 get 和 set 的对象。 其实大致意思…

公有云——阿里云ECS服务器入门精通(IaaS)(2)

作者简介&#xff1a;一名云计算网络运维人员、每天分享网络与运维的技术与干货。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​​ 目录 一.ECS 实例规格族介绍 1.实例的架构类型、规格分类&#xff0c;详细信息 2.企业…

网络互联与互联网 - IP 子网划分详解

文章目录 1 概述1.1 划分目的1.2 划分原则1.3 子网掩码 2 IP 子网划分示例3 网工软考真题3.1 判断网络号和主机号3.2 计算可容纳的主机数3.3 子网划分 1 概述 IP 子网划分&#xff1a;实际上就是设计 子网掩码 的过程。原因&#xff1a;由于在五类的IP地址中&#xff0c;网络号…

【SpringBoot】数据校验API

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ 数据校验API SpringBoot数据校验数据校验API的…

智能电动「唱主角」,哪些供应商在「领跑」智驾域控制器赛道

新势力&#xff0c;从哪里突围&#xff1f; 造车新势力在过去几年的成绩&#xff0c;已经代表了未来趋势&#xff1a;新能源汽车&#xff0c;尤其是纯电动。而对于智能化软硬件供应商&#xff0c;尤其是新势力供应商来说&#xff0c;亦是如此。 高工智能汽车研究院监测数据显…

深度学习框架-Tensorflow2:特点、架构、应用和未来发展趋势

引言 深度学习是一种新兴的技术&#xff0c;已经在许多领域中得到广泛的应用&#xff0c;如计算机视觉、自然语言处理、语音识别等。在深度学习中&#xff0c;深度学习框架扮演着重要的角色。Tensorflow是一种广泛使用的深度学习框架&#xff0c;已经成为深度学习的事实标准。…

全民拼购为什么能躺赢

大家好&#xff01;我叫小鱼 新商业&#xff0c;新模式 新机会&#xff01; 我们在拼购过程中 往往都觉得商家在亏钱 事实如此吗&#xff1f; 随着全球经济下行&#xff0c;党中央、国务院 高度重视发展流通扩大消费。 为推动流通创新发展&#xff0c;促进商业繁荣&#xff0c;…

回文子串问题

一&#xff1a;最长回文子串&#xff08;leetcode 5&#xff09; 给你一个字符串 s&#xff0c;找到 s 中最长的回文子串。 如果字符串的反序与原始字符串相同&#xff0c;则该字符串称为回文字符串。 示例 1&#xff1a; 输入&#xff1a;s "babad" 输出&#x…

盛元广通疾病预防控制中心检测管理信息系统

近些年&#xff0c;在疾病预防控制领域&#xff0c;公共卫生事件的发生都是通过信息化手段在日常工作中加以应用以及广泛深入的探索&#xff0c;加快疾控实验室信息化建设进程&#xff0c;可以有效把控不同类型检测任务中的每个节点&#xff0c;严防不同系统填报多次出现信息误…