C++构造函数

news2024/11/24 4:18:25

构造函数详解

类的6个默认的成员函数:

类中如果什么都没有定义:---有六个默认的成员函数:

  1. 构造函数:主要完成对象的初始化工作
  2. 析构函数:主要完成对象中资源的清理工作
  3. 拷贝构造函数:拷贝一个新的对象
  4. 赋值运算符重载: 让两个对象之间进行赋值
  5. 引用的重载:普通和const类型--->对对象进行引用
  6. 如果类中没有显式定义(程序员没有定义),编译器会宫动豳成一个默认的,构造函数

构造函数的概念:

  • 构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,保证每个数据成员都有一个合适的初始值,并且在对象的生命周期内只调用一次。

构造函数的特性

  • 函数名与类名相同。
  • 无返回值。
  • 编译器自动调用对应的构造函数。
  • 构造函数可以重载。

为什么要引出构造函数这一概念

  • 看下面的代码,对于Date类,可以通过InitDate公有的方法给对象设置内容,但是如果每次创建对象都调用该方法设置信息,未免有点麻烦,那能否在对象创建时,就将信息设置进去呢?
  • 现在我们的需求就是不通过对象去调用初始化对象的数据,我们希望当这个对象创建出来的时候,他就已经是具有一定的初始值的,那么如何做到我们现在的这个需求的呢?
  • 由此,引入了构造函数这一个概念,如下所示:
#include<iostream>
using namespace std;
class Date
{
public:
	void InitDate(int year, int month, int day)   //进行初始化的操作
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void PrintDate()   //打印进行检测
	{
		cout << _year << "/" << _month << "/" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1, d2, d3;

	d1.InitDate(2020, 4, 30);
	d1.PrintDate();

	d2.InitDate(2020, 4, 29);
	d2.PrintDate();

	d3.InitDate(2020, 4, 28);
	d3.PrintDate();
}

构造函数的功能

  • 需要注意的一点是,虽然构造函数叫"构造"函数,但是构造函数并不是用来构造对象的,构造函数的功能是用来完成对象的初始化的.
#include<iostream>
using namespace std;
class Date
{
public:
	//无参的构造函数
	Date()   //构造函数  ,没有返回值
	{
		cout << "Date()" << this << endl;   //打印this是为了看当前构造的是哪一个对象
		//把对象的地址打印出来
	}
	Date(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	//两个构造函数形成了重载
	//一个是没有参数的构造函数,一个是具有三个参数的构造函数 

	//创建几个对象,编译器就会调用几次构造函数
	//调用构造函数的次数与对象的次数是相同的
	//因为构造函数调用的时机就是在创建对象的时候调用
	void InitDate(int year, int month, int day)   //进行初始化的操作
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void PrintDate()   //打印进行检测
	{
		cout << _year << "/" << _month << "/" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1, d2, d3;
	Date d4(2020, 4, 27);
	Date d5();     
	//并不是创建了一个对象
	//这是一个函数声明,相当于我是有一个函数名称
	//为d5的函数,这个函数的返回值类型是Date类型,没有参数


	d1.InitDate(2020, 4, 30);
	d1.PrintDate();

	d2.InitDate(2020, 4, 29);
	d2.PrintDate();

	d3.InitDate(2020, 4, 28);
	d3.PrintDate();

	d4.PrintDate();

}

如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义编译器将不再生成

  • 当然,前提是,只有用户没有显示定义构造函数的时候,编译器才会去生成默认的构造函数
#include<iostream>
using namespace std;
class Date
{
public:
	//无参的构造函数
	//Date()   //构造函数  ,没有返回值
	//{
	//	cout << "Date()" << this << endl;   //打印this是为了看当前构造的是哪一个对象
	//	//把对象的地址打印出来
	//}
	//Date(int year, int month, int day)
	//{
	//	_year = year;
	//	_month = month;
	//	_day = day;
	//}
	//两个构造函数形成了重载

	//创建几个对象,编译器就会调用几次构造韩素
	void InitDate(int year, int month, int day)   //进行初始化的操作
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void PrintDate()   //打印进行检测
	{
		cout << _year << "/" << _month << "/" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1;
	//编译器生成的构造函数是默认的构造函数
	//默认的构造函数一定是无惨的
	//如果说,用户定义构造函数了,编译器就不会生成的
	//如果这个时候再创建一个带有三个参数的对象的话
	//就一定是不会创建成功的
	//对象创建成功了,就说明是有默认的构造函数存在的
	return 0;
}

无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个。注意:无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数,都可以认为是默认成员函数

#include<iostream>
using namespace std;
class Date
{
public:
	//无参的构造函数
	Date()   //构造函数  ,没有返回值
	{
		cout << "Date()" << this << endl;   //打印this是为了看当前构造的是哪一个对象
		//把对象的地址打印出来
	}

	//全缺省的构造函数
	Date(int year=2000, int month=1, int day=1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	//两个构造函数形成了重载

	//创建几个对象,编译器就会调用几次构造函数
	void InitDate(int year, int month, int day)   //进行初始化的操作
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void PrintDate()   //打印进行检测
	{
		cout << _year << "/" << _month << "/" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1;
}

上面的代码,是会报错的,无法通过编译,报错的内容是—“Date::Date”:对重载函数的调用不明确,因为上面的代码中,有两个默认的构造函数,因为不带参数的构造函数和全缺省的构造函数都被看为默认的构造函数,所以说,现在有两个构造函数,编译器不知道到底要去调用哪个构造函数,所以说,就会报错,所以说,默认的构造函数只能存在有一个,下面的代码就可以通过编译了:

#include<iostream>
using namespace std;
class Date
{
public:
	//全缺省的构造函数
	Date(int year = 2000, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	//两个构造函数形成了重载

	//创建几个对象,编译器就会调用几次构造函数
	void InitDate(int year, int month, int day)   //进行初始化的操作
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void PrintDate()   //打印进行检测
	{
		cout << _year << "/" << _month << "/" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1;
}

  关于编译器生成的默认成员函数,很多人会有疑惑:在我们不实现构造函数的情况下,编译器会生成默认的构造函数。但是看起来默认构造函数又没什么用?d对象调用了编译器生成的默认构造函数,但是d对象year/month/_day,依旧是随机值。也就说在这里编译器生成的默认构造函数并没有什么用?

  • 解答:C++把类型分成内置类型(基本类型)和自定义类型。内置类型就是语法已经定义好的类型:如int/char…,自定义类型就是我们使用class/struct/union自己定义的类型,看看下面的程序,就会发现编译器生成默认的构造函数会对自定类型成员_t调用的它的默认成员函数
class Time
{
public:
	Time()
	{
		cout << "Time()" << endl;
		_hour = 0;
		_minute = 0;
		_second = 0;
	}
private:
	int _hour;
	int _minute;
	int _second;
};
class Date
{
private:
	// 基本类型(内置类型)
	int _year;
	int _month;
	int _day;
	// 自定义类型
	Time _t;
};
int main()
{
	Date d;
	return 0;
}

成员变量的命名风格 

// 我们看看这个函数,是不是很僵硬?
class Date
{
public:
	Date(int year)
	{
		// 这里的year到底是成员变量,还是函数形参?
		year = year;
	}
private:
	int year;
};
// 所以我们一般都建议这样
class Date
{
public:
	Date(int year)
	{
		_year = year;
	}
private:
	int _year;

};
// 或者这样。
class Date
{
public:
	Date(int year)
	{
		m_year = year;
	}
private:
	int m_year;
};
// 其他方式也可以的,主要看公司要求。一般都是加个前缀或者后缀标识区分就行。

再谈构造函数

问题:构造函数体中的语句是不是初始化?

  • 赋值和初始化的区别----赋值是可以进行多次赋值的,但是初始化的话,只能进行一次的初始化操作
  • 可以通过如下的方式进行验证,验证到底是初始化还是赋值

  • 发现上述的代码编译成功了,所以说明构造函数体中不是初始化,而是赋值

  • 上述代码中a为const类型的变量,对代码进行编译之后,发现代码无法通过编译,也就更加证实了,构造函数体内是赋值而并非是初始化,因为const类型的成员无法进行赋值的操作

构造函数体赋值

  • 在创建对象时,编译器通过调用构造函数,给对象中各个成员变量一个合适的初始值
  • 构造函数最主要是用来完成对象的初始化的工作的,但是我们在构造函数函数体内进行的赋值操作虽然说也可以把给参数的值放到对象里面去,但是构造函数函数体里面不是初始化,因为是赋值操作,那么我们如何来判断构造函数函数体里面是赋值还是初始化呢?我们可以使用一个在定义的时候必须进行初始化的东西来判断构造函数函数体里面到底是赋值还是初始化。那么很容易想到的就是引用在定义的时候必须进行初始化操作,那么我们可以在private定义的变量中引入一个引用变量,给了引用变量之后是会报错的,那么就说明构造函数函数体里面的操作其实是赋值而不是初始化的操作
class Date
{
public:
    Date(int year, int month, int day)
    {
        _year = year;
        _month = month;
        _day = day;
    }
private:
    int _year;
    int _month;
    int _day;
};
  • 虽然上述构造函数调用之后,对象中已经有了一个初始值,但是不能将其称作为类对象成员的初始化,构造函数体中的语句只能将其称作为赋初值,而不能称作初始化。因为初始化只能初始化一次,而构造函数体内可以多次赋值
  • 所以得出结论—构造函数函数体中是赋值不是初始化

初始化列表的概念 

  • 构造函数具有初始化列表,并且只有工造函数具有初始化列表,别的函数都没有初始化列表
  • 初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括号中的初始值或表达式
#include<iostream>
using namespace std;
class Date
{
public:
	Date(int year, int month, int day)
		:_year(year),
		_month(month),
		_day(day)
	{
		cout << "Date(int year, int month, int day)" << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

  • 那么如何验证初始化列表是初始化而不是赋值呢?
  • 因为我们是知道的,赋值是可以进行多次的,但是初始化只能初始化一次,那么我们就可以利用这个性质,在初始化列表中让一个变量出现多次,如果代码报错的话,那么就说明初始化列表是初始化而不是赋值了,如下所示,下面的代码时会报错的
#include<iostream>
using namespace std;
class Date
{
public:
	Date(int year, int month, int day)
		:_year(year),
		_month(month),
		_day(day),
		_day(day)
	{
		cout << "Date(int year, int month, int day)" << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
  • 报错内容是_day已经初始化了 
  • 初始化只能初始化一次,如果多次进行初始化操作的话,代码就会报错
  • 就好像是一个人不能多次出生是一样的道理

初始化列表的功能 

  • 初始化列表就是专门就是为了对类中各个成员变量进行初始化的操作,而初始化呢他不是可以初始化两次的,所以一个变量如果初始化两次的话就会出错。因为在对变量进行初始化的时候需要为变量开辟内存空间,如果已经为一个变量开辟了内存空间的话,就不需要为那个变量再次开辟内存空间了。 一个变量开辟两个空间肯定是有问题的
  • 初始化列表并没有规定各个变量出现的次序,就算初始化列表的次序和形参出现的次序是不一样的,代码也是不会报错的,所以说,初始化列表并没有强制规定参数的次序要和形参的次序是一样的。但是一般情况下不建议这么做,防止出现像这样的问题

  

为什么month会是随机值呢,因为编译器先去初始化year,然后初始化year完成之后,编译器开始去初始化month,但是初始化列表给的是用day去初始化month,但是此时day并没有进行初始化的操作,所以最终看出,month为随机值。

注意事项

  • (1)初始化列表中成员的出现次序,不代表其真正的初始化次序
  • (2)成员变量在初始化列表中的初始化次序为其在类中的声明次序
  • 建议:最好不要使用成员初始化成员
  • 虽然说我们可以把_day写在_month的前面,但是我们在初始化的时候,还是先去初始化的_month然后再去初始化的_day
  • 编译器是不会按照我们所给出的初始化的顺序来进行初始化的,编译器是按照形参出现的顺序来进行初始化操作的

 拷贝构造函数也可以有初始化列表

#include<iostream>
using namespace std;
class Date
{
public:
	Date(const Date& d)
		: _year(d._year)
		, _month(d._month)
		, _day(d._day)
	{
		// 		_year = d._year;
		// 		_month = d._month;
		// 		_day = d._day;
		cout << "Date(Date&):" << this << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

引用变量以及const类型的变量的注意事项 

  • 每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)
  • 类中包含以下成员,必须放在初始化列表位置进行初始化:(在构造和拷贝构造的地方都需要进行初始化)
  • (1)引用成员变量
  • (2)const成员变量

#include<iostream>
using namespace std;
class Date
{
public:
#if 0
	// 初始化列表
	Date(int year = 1900, int month = 1, int day = 1)
		: _year(year)
		, _month(month)
		, _day(day)
	{
		// 构造函数体中是赋初值不是初始化
// 		_year = year;
// 		_month = month;
// 		_day = day;
		//r = _day;
		cout << "Date(int,int,int):" << this << endl;
	}
#endif

	// 初始化列表
	// 1. 初始化列表中成员的出现次序,不代表其真正的初始化次序
	// 2. 成员变量在初始化列表中的初始化次序为其在类中的声明次序
	// 建议:最好不要使用成员初始化成员
	Date(int year = 1900, int month = 1, int day = 1)
		: _year(year)
		, _month(month)
		, _day(day)
		, _r(_day)
		, _a(_day)
	{
		// 构造函数体中是赋初值不是初始化
		// 		_year = year;
		// 		_month = month;
		// 		_day = day;
		//r = _day;
		cout << "Date(int,int,int):" << this << endl;
	}

	Date(const Date& d)
		: _year(d._year)
		, _month(d._month)
		, _day(d._day)
		, _r(d._r)
		, _a(d._a)
	{
		// 		_year = d._year;
		// 		_month = d._month;
		// 		_day = d._day;
		cout << "Date(Date&):" << this << endl;
	}

	// d1 = d2 = d3;
	Date& operator=(const Date& d)
	{
		cout << this << "=" << &d << endl;
		if (this != &d)
		{
			_year = d._year;
			_month = d._month;
			_day = d._day;
		}

		return *this;
	}

	~Date()
	{
		cout << "~Date():" << this << endl;
	}


	int _year;
	int _month;
	int _day;
	int& _r;
	const int _a;
};
  • (3)类类型成员(该类没有默认构造函数)
#include<iostream>
using namespace std;
class 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)
		, _t(0, 0, 0)
		//, _t()   //调用无参的默认的构造函数
	{
		cout << "Date(int,int,int):" << this << endl;
	}

private:
	int _year;
	int _month;
	int _day;
	Time _t;
	//如果没有上面的_t(0, 0, 0),直接给出Time_t是会报错的,原因在于
	//声明了一个time类的对象t,那么这个对象t一定是需要进行初始化的
	//那么编译器会默认去Time类中寻找没有参数的构造函数,但是Time类此时是没有
	//显示给出无参的构造函数的,所以就会出错
	//那么我们为了可以正确的创建出来这个Time类类型的对象的话,那么我们就需要给出来一个有参数的
	//就好比说_t(0, 0, 0),就可通过编译了
};

int main()
{
	//Date d(2019, 3, 24);
	Date d;
	return 0;
}
  • 尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使用初始化列表初始化。(没写并不代表没有,还是会去调用相应的函数的)
  • 其实也就是说,就算你的构造函数函数体里面什么都没有,他也是会优先去执行构造函数的初始化列表,所以,尽量还是使用初始化列表来进行初始化操作。
  • 调试起来的话,会首先停在构造函数函数名的位置上,并没有直接走到了函数体的内部
  • 看起来构造函数没有写初始化列表,但是需要注意,没有写并不代表没有,因为如果用户没有写的话,其实编译器是会自动去加上的,只不过一般情况下成员变量是用随机值进行初始化的
  • 要先初始化好,才能进入到构造函数的函数体中

 

#include<iostream>
using namespace std;
class Time
{
public:
	Time(int hour = 0, int minute = 0, int second = 0)
		: _hour(hour)
		, _minute(minute)
		, _second(second)
	{
		cout << this->_hour << endl;
	}

	void TestFunc()
	{}

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)
				//, _t()   //调用无参的默认的构造函数
	{
		cout << "Date(int,int,int):" << this << endl;
	}

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

  • 成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关,也就是说,不是按照我给的初始化列表的次序来进行初始化操作的,编译器是按照声明的次序来进行初始化的(上面已经提到过了)

提问,在初始化列表中如何知道对象已经构造好了? 

  • 就是在构造函数的初始化列表完成之后,去打印一下this,如果代码可以正常的通过编译,那么就说明我的对象是构造好了的
#include<iostream>
using namespace std;
class Time
{
public:
	Time(int hour = 0, int minute = 0, int second = 0)
		: _hour(hour)
		, _minute(minute)
		, _second(second)
	{
		cout << this<< endl;    //我的意图是要去打印this,然后发现代码可以正常通过编译
		//那么,也就是说,此时,我的对象已经构造好了
	}
private:
	int _hour;
	int _minute;
	int _second;
};

两个问题

在构造函数有没有把对象的地址传递过去呢?

  • 对象的地址一定是传递过来了的,如果对象的地址没有传递过来的话,那儿我怎么知道当前构造的是那个对象呢?所以说对象的地址一定是已经传递过来了的

  • 008560677 把t的首地址放到了exc寄存器里面,然后去调用Time类的函数
  • 在构造函数调用之前,对象是不存在的,因为构造函数的目的就是用来初始化对象的,虽然对象本身是并不存在的,但是对象的空间是存在的,所以也就是说,在我们没有调用构造函数之前,我们就已经有了一段空间了,因为编译器是要进行编译的,所以他必须提前计算出这个对象需要多大的栈空间

  • 定义了两个对象,所以编译器必须要在编译期间计算出这两个对象的大小,因为不可能做到一边运行一边修改,所以说,必须要提前计算好,在编译的时候是不会调用构造函数的,是在运行的时候去调用的

在构造函数的初始化列表的位置可不可以使用this指针呢? 

  • 在构造函数初始化列表的位置还不能使用构造函数,因为this是指向当前对象的,初始化列表的位置,当前对象还并没有构造好,所以还是不能使用的,还没有真正的区划分空间。但是在函数体里面是完全可以,因为对象已经完全的初始化完成了,是 可以正常去使用的
#include<iostream>
using namespace std;
class Time
{
public:
	Time(int hour = 0, int minute = 0, int second = 0)
		: _hour(hour)
		, _minute(minute)
		, _second(second)
	{
		cout << this->_hour << endl;
	}

	void TestFunc()
	{}

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)
				//, _t()   //调用无参的默认的构造函数
	{
		cout << "Date(int,int,int):" << this << endl;
	}

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

int main()
{
	// 在编译器编译期间,已经为main分配好了栈空间
	// 该空间中已经包含了函数体中的局部对象
	Date d;    // 在构造函数调用之前,对象是不存在的
	Time t;
	t.TestFunc();

	return 0;
}

结论:也就是说对象的空间早就已经给好了,只不过缺的是构造函数,构造函数的功能就是把对象中各个成员变量给其初始化好就可以了

构造函数的功能:

  • 构造函数不仅就有初始化成员变量的功能,还具有类型转化的功能

  • 因为单参的构造函数代码可读性太差,所以我们一般就把单参的构造函数的类型转换的功能给他禁止掉,用下面的关键字进行禁止

explicit关键字 

  • 构造函数不仅可以构造与初始化对象,对于单个参数的构造函数,还具有类型转换的作用

#include<iostream>
using namespace std;
class Date
{
public:
	Date(int year)
		: _year(year)
	{
		cout << "Date(int,int,int):" << this << endl;
	}

	Date& operator=(const Date& d)
	{
		return *this;
	}

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


int main()
{
	Date d(2019);
	d = 2020;   
	//一个是日期类型的变量,一个是整形的变量,在我们之前想的是,这时不能通过编译的
	//但是没想到,这样的代码是可以通过编译的,原因在于
	// 2020---> 通过单参构造函数--->临时对象
	//也就是说构造函数具有类型转换的功能,本来是一个int类型,然后被转换了
	// 用一个整形变量给日期类型对象赋值
	// 实际编译器背后会用2020构造一个无名对象,最后用无名对象给d1对象进行赋值
	//但是一般情况下,会把这种类型转换禁止掉,那么如何来禁止呢?
	//禁止的方法就是在构造函数前面加上一个explicit关键字
	return 0;
}
  • 上述代码可读性不是很好,用explicit修饰构造函数,将会禁止单参构造函数的隐式转换。
#include<iostream>
using namespace std;
class Date
{
public:
	explicit Date(int year)
		: _year(year)
	{
		cout << "Date(int,int,int):" << this << endl;
	}

	Date& operator=(const Date& d)
	{
		return *this;
	}

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


int main()
{
	Date d(2019);
	d = 2020;   // 2020---> 通过单参构造函数--->临时对象
	return 0;
}

之前说过的几个默认的构造函数,如果我么没有显示给出的话,编译器会生成默认的 

#include<iostream>
using namespace std;
class Date
{
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d;
	return 0;
}
  • 问题来了,什么时候编译器会生成默认的?-------答案就是—>如果编译器感觉自己需要的时候就会生成,那么问题又来了,什么才是编译器需要的时候(一共有四种场景)
#include<iostream>
using namespace std;
class Time
{
public:
	Time(int hour = 0, int minute = 0, int second = 0)
		: _hour(hour)
		, _minute(minute)
		, _second(second)
	{
		cout << this->_hour << endl;
	}

	Time(Time&)
	{}

	Time& operator=(Time& t)
	{
		return *this;
	}

	~Time()
	{}

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

class Date
{
public:
	// 	Date()
	// 	{}

		/*
		Date(Date& d)
		   : _t(d._t)
		{}

		*/

private:
	int _year;
	int _month;
	int _day;
	Time _t;
};
int main()
{
	Date d1; // 日期类的构造函数 // Time()
	Date d2(d1);  // Time(Time&)--->找个调用位置--->Date类的拷贝构造函数中
	Date d3;
	d3 = d1;
	return 0;
}
  • (1)现在有A类和B类两个类,B类中包含A类的对象,A类中有缺省的构造函数,B类中没有定义任何的构造函数,编译器此时就会生成默认的构造函数
  • (2)Time(Time&)—>找个调用位置—>Date类的拷贝构造函数中
  • (3)赋值也是一样的

  谢谢大家的支持! 

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

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

相关文章

【Vue】VueCLI 的使用和单文件组件(2)

首先作为一个工程来说&#xff0c; 一般我们的源代码都放在src目录下&#xff1a; 外面的代码我们先不去管它&#xff0c;后面在工程编写的时候再给大家仔细的介绍。‍‍ 这块大家主要知道我们的源代码 都在src里面&#xff0c;它的入口文件是一个man点js文件&#xff0c;‍‍…

【day21】每日一题——MP3光标位置

MP3光标位置_牛客题霸_牛客网 这题就是简单的根据它的规则把它的情况都列举出来即可&#xff08;当然&#xff0c;我第一次写一脸懵逼&#xff0c;所以你现在一脸懵逼没事&#xff0c;看完你就觉得简单了。看完还懵逼&#xff0c;你就多看几遍&#xff0c;然后自己去尝试一下&a…

C/C++,不废话的宏使用技巧

经典废话 下面的所有内容全是我在欣赏一串代码时发出的疑问&#xff0c;之前对宏的了解不多&#xff0c;导致在刚看到下面的这串代码的时候是“地铁 老人 手机”&#xff0c;具体代码如下&#xff0c;如果有对这里解读有问题的欢迎在评论区留言。 一、预定义宏 编译一个程…

在线就能制作活动邀请函,一键生成链接

今天小编教你如何在线制作一个活动邀请函&#xff0c;不需要下载软件&#xff0c;也不需要编程代码&#xff0c;只需使用乔拓云工具在线一键就能生成活动邀请函和邀请函链接&#xff0c;下面就跟着小编的教学开始学习如何在线制作活动邀请函&#xff01;第一步&#xff1a;打开…

[附源码]java毕业设计SSM归途中流浪动物收容与领养管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

OSPF高级配置——虚接口,NSSA

作者介绍&#xff1a; 作者&#xff1a;小刘在C站 每天分享课堂笔记&#xff0c;一起努力&#xff0c;共赴美好人生&#xff01; 夕阳下&#xff0c;是最美的绽放。 目录 一.ospf 虚链路 二.虚链路的目的 三.配置虚链路的规则及特点 四.虚链路的配置&#xff1a; nssa …

HTML小游戏6 —— 《高达战争》横版射击游戏(附完整源码)

&#x1f482; 网站推荐:【神级源码资源网】【摸鱼小游戏】&#x1f91f; 风趣幽默的前端学习课程&#xff1a;&#x1f449;28个案例趣学前端&#x1f485; 想寻找共同学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】&#x1f4ac; 免费且实用的计算机相关知…

奥密克戎 (Omicron) 知多少m?| MedCheExpress

这个冬天 Omicron 已迅速超越其他变种&#xff0c;成为主要的 SARS-CoV-2 毒株&#xff0c;尽管该变体在体内引起的病毒水平与其“竞争对手” Delta 相比更低&#xff0c;但威力不容小觑。 ■ 第五大变异关注病毒株&#xff0c;有何神奇之处&#xff1f; 2021 年 11 月 24 日&…

深度自定义mybatis

> 回顾mybatis的操作的核心步骤 > > 编写核心类SqlSessionFacotryBuild进行解析配置文件 > 深度分析解析SqlSessionFacotryBuild干的核心工作 > > 编写核心类SqlSessionFacotry > 深度分析解析SqlSessionFacotry干的核心工作 > 编写核心类SqlSession &…

【面试官让我十分钟实现一个链表?一个双向带头循环链表甩给面试官】

我们在面试中面试官一般都会让我们现场写代码&#xff0c;如果你面试的时候面试官让你十分钟写一个链表&#xff0c;你是不是懵逼了&#xff1f;十分钟写一个链表&#xff0c;怎么可能&#xff1f;事实上是有可能的&#xff0c;十分钟写出的链表也能震惊面试官。 我们学习单链…

《红楼梦》诗词大全

前言&#xff1a; 博主最近二读红楼&#xff0c;幼时只觉此书开篇便人物繁杂、莺莺燕燕似多混乱&#xff0c;开篇只看黛玉哭闹了几次&#xff0c;便弃书不读&#xff0c;只觉困惑&#xff0c;其何敢称六大奇书或四大名著&#xff1f; 今日书荒&#xff0c;偶然间再次拾起红楼…

3.2 网络协议

0 socket协议 访问 Internet 使用得最广泛的方法&#xff1b;所谓socket通常也称作"套接字"&#xff0c;用于描述IP地址和端口&#xff0c;是一个通信链的句柄&#xff1b;应用程序通常通过"套接字"向网络发出请求或者应答网络请求&#xff1b;Socket接口…

六六大顺 马蹄集

六六大顺 难度&#xff1a;白银 0时间限制&#xff1a;1秒 巴占用内存&#xff1a;64M 输入正整数N,输出N以内&#xff08;含N),6的倍数&#xff0c;并且包含6的数字&#xff0c;比如36等。 格式 输入格式&#xff1a;输入整型 输出格式&#xff1a;输出整型&#xff0c;空格分…

SI24R1国产低功耗2.4GHz收发一体射频遥控工控答题卡方案芯片替代NRF24L01+

目录SI24R1简介芯片特性硬件设计参考2.4GHz射频芯片选型参考应用领域SI24R1简介 Si24R1 2.4GHz收发一体芯片量产于2012年&#xff0c;由于其一致性稳定性高、低功耗、远距离、兼容替代NRF24L01&#xff0c;兼容NORDIC 2.4GHz协议等特点&#xff0c;一直广泛应用于各物联网场景…

牛客竞赛每日俩题 - 动态规划2

目录 经典DP - 走方格 走方格2.0 分割回文串 分割回文串 - 回文优化 经典DP - 走方格 不同路径的数目(一)_牛客题霸_牛客网 状态&#xff1a; 子状态&#xff1a;从(0,0)到达(1,0),(1,1),(2,1),...(m-1,n-1)的路径数 F(i,j): 从(0,0)到达F(i,j)的路径数 状态递推&#xff1a…

【23届秋招总结系列】一个普本23届小学弟的秋招总结,上岸金山云开发(云计算方向)

大家好&#xff0c;我是路飞~ 正值秋招收尾阶段&#xff0c;今天很荣幸请来了交流qun小分队里的一位23届本科上岸 金山云开发工程师-云计算方向的同学&#xff0c;给大家分享一下他在秋招过程中的总结和心得体会。 他的博客链接&#xff1a;团子的守护 一、秋招收获 2022.1…

计算机毕业设计SSM大学生创新创业项目活动管理平台【附源码数据库】

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

【微服务】Nacos服务发现源码分析

&#x1f496;Spring家族及微服务系列文章 ✨【微服务】SpringBoot监听器机制以及在Nacos中的应用 ✨【微服务】Nacos服务端完成微服务注册以及健康检查流程 ✨【微服务】Nacos客户端微服务注册原理流程 ✨【微服务】SpringCloud中使用Ribbon实现负载均衡的原理 ✨【微服务】Sp…

Ubuntu20.04安装k8s v1.21.0

1. 禁用swap分区, 修改网络配置 sudo vim /etc/fstab 把有swap的那一行注释掉即可&#xff0c;如下&#xff1a; 然后执行如下命令 cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-ip6tables 1 net.bridge.bridge-nf-call-iptables 1 EOF …

12.帖子模块——使用peewee创建多表关联的结构,使用Tornado创建查询接口、增加接口

1.模型建立与数据初始化 1.1分析建立表所需要的字段 本次主要是添加一个帖子展示时&#xff0c;所需要的内容&#xff0c;这里就得创建一个mysql的数据表去存储它的内容。 1.2 使用peewee创建多表关联结构Model 模型建立 # forum/models.py # 用于创建数据表模型from peewe…