关闭

类和六个默认函数及this指针

标签: classthis指针构造函数析构函数
293人阅读 评论(0) 收藏 举报
分类:

类是c++中的一种自定义类型,用关键字class,来进行定义,很像C语言中的结构体但又有不同

class Date
{
	int _year;
	int _month;
	int _day;
	double _data;
};


这是一个最简单的类,类中的成员变量类型可以各不相同,不同于结构体的是,类中成员的默认属性为私有(private),在类外不能对类的成员变量进行访问,形成一种封装,是对成员变量的一种保护。在类中还可以声明或定义一些成员函数,一般用public限定为公有属性,在类外可以对成员函数进行调用,在类外定义函数时需在类中声明函数,定义时在函数名前加上类名和域运算符"::"

class Date
{	
public:
void Fun1()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};



在类的成员函数中可以访问类的成员变量,实际上是通过一个指向类对象的指针实现的,称为this,调用函数时编译器自动传递了这个this指针作为一个参数给被调用函数,this指针始终指向本类对象,this指针和类成员函数不属于类,不影响sizeof(类名)的结果。上述代码在编

class Date
{
public:
void Fun1()
	{
		cout <<this->_year << "-" <<this-> _month << "-" <<this->_day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};



类存在6个默认的成员函数,若未显示定义,编译器会自动合成



构造函数:类的一个特殊成员函数,不需要返回值,函数名和类名相同,在类对象被创建时自动调用构造函数,进行类对象的一些初始化工作,若未显示定义则由编译器自动合成,构造函数有初始化列表但可以不使用,构造函数分为初始化阶段和普通计算阶段,初始化的顺序与变量在类中的定义顺序一致,与初始化列表的顺序无关,所以一般不宜用一个变量初始化另一个变量。另外,构造函数可以进行重载,具体调用哪个构造函数根据所给参数决定,

class Date
{
public:
	Date()                                                       //构造函数1
		:_year(2016)
		, _month(10)
		, _day(10)
	{}                                          
	Date(int year = 2016, int month = 6, int day = 1)             //构造函数2
		:_year(year)
		, _month(month)
		, _day(day)
	{
		cout << "Date()" << endl;
	}                                                                                                                  private:
	int _year;
	int _month;
	int _day;
};


在函数体内可进行编写者想要的操作,另外,编译器自动合成的构造函数给类成员变量赋随机值,若类只含有一个成员变量,则进行隐式转换,将成员类型隐式转换为一个类类型,用类创建对象时可直接对对象进行赋值。此时构造函数又可称为转换构造函数。

对构造函数总结一下:

1、函数名与类名相同
2、不需要返回值
3、有初始化列表,(可以不用)
4、新对象被创建时,编译器自动调用构造函数,对象生命周期内仅调用一次
5、若未显示定义,编译器自动合成构造函数
6、构造函数可以重载,实参决定调用哪个构造函数
7、无参或全缺省的构造函数都被认为是缺省的构造函数,缺省构造函数只能有一个
8、构造函数不能使用const修饰(无法修改成员变
9、若类中只有一个成员变量,城建对象时可直接对对象进行赋值,编译器自动将赋值内容隐式转换为类类型,若要防止这种隐式转换,可用关键字explicit对构造函数进行修饰     
10、构造函数的作用:(1)构建对象那 (2)初始化对象(3)进行类型转换:(1)构建对象那 (2)初始化对象(3)进行类型转换



接下来是拷贝构造函数,首先它也是一个构造函数,拥有构造函数的特性,在使用对象来创建对象时调用,拷贝构造函数也不需要返回值,函数名与类名相同,有一个参数,为同类对象的引用,一般用const对其修饰,防止对此对象进行修改,简单说拷贝构造函数的作用就是进行对一个对象的拷贝

class Date
{
public:
	Date()                                                       //构造函数1
		:_year(2016)
		, _month(10)
		, _day(10)
	{}                                          
	Date(int year = 2016, int month = 6, int day = 1)             //构造函数2
		:_year(year)
		, _month(month)
		, _day(day)
	{
		cout << "Date()" << endl;
	}
	Date(const Date& A)                                           //拷贝构造函数                                                             
	{
		cout << "Date(const Date& A)" << endl;
	}                                                                                                                                  
private:
	int _year;
	int _month;
	int _day;
};

总结:

  1、是构造函数的重载,拥有构造函数的一些特性(返回值,函数名,函数组成)
  2、函数参数必须使用同类型对象的引用传递。   
  3、如果没有显式定义,系统会自动合成一个默认的拷贝构造函数。默认的拷贝构造函数会依次拷贝类的数据成员完成初始化。
 

析构函数,作用与构造函数刚好相反,在对象呗销毁时由编译器自动调用,完成类的一些资源清理和汕尾工作,类生命周期内仅调用一次,同样没有返回值,函数名为类名前加"~"

class Date
{
public:
	Date()                                                       //构造函数1
		:_year(2016)
		, _month(10)
		, _day(10)
	{}                                          
	Date(int year = 2016, int month = 6, int day = 1)             //构造函数2
		:_year(year)
		, _month(month)
		, _day(day)
	{
		cout << "Date()" << endl;
	}
	Date(const Date& A)                                           //拷贝构造函数
		:_year(A._year)
		, _month(A._month)
		, _day(A._day)
	{
		cout << "Date(const Date& A)" << endl;
	}
	~Date()                                                       //析构函数
	{
		cout << "~Date" << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

总的来说析构函数比较简单,总结一下:

1、析构函数在类名加上字符~。
 2、析构函数无参数无返回值。
 3、一个类有且只有一个析构函数。若未显示定义,系统会自动生成缺省的析构函数。
 4、对象生命周期结束时,C++编译系统系统自动调用析构函数。
 5、析构函数体内并不是删除对象,而是做一些清理工作。


除了以上三个函数,还有一个与类有关的函数不得不提:友元函数

友元函数是定义在类外的普通函数,在类中加friend修饰为类的友元函数,在友元函数中可访问类的私有成员,但友元函数不属于类的的成员函数,所以不受public以及private限定,也不存在默认的this指针。写一个友元函数

class Date
{
public:
	Date()                                                       //构造函数1
		:_year(2016)
		, _month(10)
		, _day(10)
	{}                                          
	Date(int year = 2016, int month = 6, int day = 1)             //构造函数2
		:_year(year)
		, _month(month)
		, _day(day)
	{
		cout << "Date()" << endl;
	}
	Date(const Date& A)                                           //拷贝构造函数
		:_year(A._year)
		, _month(A._month)
		, _day(A._day)
	{
		cout << "Date(const Date& A)" << endl;
	}
	~Date()                                                       //析构函数
	{
		cout << "~Date" << endl;
	}
friend void Fun3(const Date& B);                                      //友元函数
private:
	int _year;
	int _month;
	int _day;
	double _data;
};


void Fun3(const Date& B)
{
	cout << "friend " << B._year << B._month << B._day << endl;
}

友元函数必须在类中声明,在类外定义。友元函数可以提高程序的运行效率,但会破坏程序的封装和隐蔽。总结一下友元函数:

1、友元函数可访问类的私有成员,但不是类的成员函数;
2、友元函数可以在类定义的任何地方声明,不受类访问限定符限制;
3、一个函数可以是多个类的友元函数;
4、友元函数的调用与普通函数的调用和原理相同;                                                                                             5、友元关系不能传递;  
6、友元关系是单向的,不具有交换性.


操作符重载:操作符重载是具有特殊函数名的函数,关键字opreator后加要进行重载的操作符,操作符重载也是一个函数,具有返回值和形参表。它的形参数目与操作符的操作数目相同,函数调用操作符可以接受任意数目的操作数。类的赋值操作符重载和取址操作符重载时类的两个默认成员函数,若编写者未进行定义也可调用,要对类进行其他的操作符运算则必须进行操作符重载,重载符号必须是现有的一些操作符,除以下五个操作符以外都可进行操作符重载:

1、 .                  成员选择符     

2、.*                 成员对象选择符

3、::                  域运算符

4、 ?:                条件操作符

5、 sizeof        


下面对日期类的"+"运算符,"="运算符,"-"运算符以及"<<"进行重载:
class Date
{
public:
	Date()                                                       //构造函数1
		:_year(2016)
		, _month(10)
		, _day(10)
	{}                                          
	Date(int year = 2016, int month = 6, int day = 1)             //构造函数2
		:_year(year)
		, _month(month)
		, _day(day)
	{
		cout << "Date()" << endl;
	}
	Date(const Date& A)                                           //拷贝构造函数
		:_year(A._year)
		, _month(A._month)
		, _day(A._day)
	{
		cout << "Date(const Date& A)" << endl;
	}
	~Date()                                                       //析构函数
	{
		cout << "~Date" << endl;
	}
	Date operator-(int days);
	Date operator+(int days);
	Date& operator=(const Date& d);
	friend ostream& operator<<(ostream& os, const Date& d);
	friend void Fun3(const Date& B);
	bool IsLeap();                                                  //判断是否为闰年
private:
	int _GetMonthDay(int month);                                    //获取当月天数

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

bool Date::IsLeap()
{
	if ((_year % 4 == 0 && _year % 100 != 0) ||
		(_year % 400 == 0))
	{
		return true;
	}
	return false;
}

ostream& operator<<(ostream& os, const Date& d)
{
	os << d._year << "-" << d._month << "-" << d._day;
	return os;
}

int Date::_GetMonthDay(int month)
{
	int day[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
	if (IsLeap() == 1 && month == 2)
	{
		return day[month] + 1;
	}
	return day[month];
}

Date& Date::operator=(const Date& d)
{
	_year = d._year;
	_month = d._month;
	_day = d._day;
	return *this;
}
Date Date::operator+(int days)
{
	_day = _day + days;
	while (_day > _GetMonthDay(_month))
	{
		_day = _day - _GetMonthDay(_month);
		_month++;
		if (_month == 13)
		{
			_month = 1;
			_year++;
		}
	}
	Date Tmp = *this;
	return Tmp;
}
Date Date::operator-(int days)
{
	_day = _day - days;
	while (_day < 1)
	{
		_month--;
		_day = _day + _GetMonthDay(_month);
		if (_month == 1)
		{
			_month = 12;
			_year--;
		}
	}
	Date tmp = *this;
	return tmp;
}

运算符重载后 可直接调用于类的一些操作,如赋值、输出、日期加天数等,操作符左侧为当前对象,操作符后为参数。总结一下运算符重载:
1、不能通过连接其他符号来创建新的操作符:比如operator@;
   void operator @(){},这样是错误的
2、重载操作符必须有一个类类型或者枚举类型的操作数
3、用于内置类型的操作符,其含义不能改变,例如:内置的整型+,不能改变其含义
5、不在具备短求职特性
   重载操作符不能保证操作符的求职顺序,在重载&&和||中,对每个操作数都要进行求值,而且对操作数的求职顺序不能做规定,因此:重载&&、||和逗号操作符不是好的做法。
6、作为类成员的重载函数,其形参看起来比操作数数目少1, 成员函数的操作符有一个默认的形参this,限定为第一个形参。
7、一般将算术操作符定义为非成员函数,将赋值运算符定义成员函数
8、操作符定义为非类的成员函数时,一般将其定义为类的友元
9、== 和 != 操作符一般要成对重载
10、下标操作符[]:需要定义两个重载函数,一个非const成员并返回引用,一个是const成员并返回引用,这样可以防止不必要的操作失误;
11、解引用操作符*和->操作符,不显示任何参数
13、自增自减操作符
    前置式++/--必须返回被增量或者减量的引用
    后缀式操作符必须返回旧值,并且应该是值返回而不是引用返回
14、输入操作符>>和输出操作符<<必须定义为类的友元函数,否则参数顺序就要颠倒成为 (类名)<<cout:










1
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:10461次
    • 积分:490
    • 等级:
    • 排名:千里之外
    • 原创:39篇
    • 转载:2篇
    • 译文:0篇
    • 评论:0条
    文章分类