您的位置:首页 > 编程语言 > C语言/C++

C++的6大成员函数,构造函数(初始化列表),析构函数,拷贝构造函数,运算符重载,const成员函数

2018-03-28 15:19 816 查看
在C++中,有6个默认的成员函数(即如果不写成员函数,系统就会自动调用)。一,构造函数构造函数是特殊的成员函数。作用是:在创建对象时,对对象进行初始化。其特征有:①构造函数是成员函数,可以写在类体外,也可以写在类体内。②函数名与类名相同。③不指定类型说明,无返回值。④实例化对象时系统自动调用。⑤构造函数可以重载。⑥如果在定义类时,没有写构造函数,系统就会自动生成一个缺省的构造函数,但是如果自己写了构造函数,系统调用写的那个函数。⑦无参的构造函数和全缺省的构造函数都是缺省的构造函数。下面我们通过一个具体的例子来认识构造函数:1.无参的构造函数
#include <iostream>
#include<windows.h>
using namespace std;
class Date
{
public:
Date()
{
cout<<"Date"<<endl;
}
void Print()
{
cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d;
d.Print();
system("pause");
return 0;
}
无参的构造函数,在创建对象初始化时,什么都不会做。此时,如果不写构造函数,也会调用系统自动生成的构造函数,同样什么也不会做。但是如果类中有自定义的类,那么用自己写的构造函数就会初始化。2.有参的构造函数
#include <iostream>
#include<windows.h>
using namespace std;
class Date
{
public:
Date(int year,int month,int day)
{
_year = year;
_month = month;
_day = day;
cout<<"Date"<<endl;
}
void Print()
{
cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d;
d.Print();
Date d1(2018,3,25);
d1.Print();
system("pause");
return 0;
}
有参的构造函数,创建对象调用构造函数初始化时的值就是传的值。3.缺省的构造函数⑤全缺省的构造函数
#include <iostream>
#include<windows.h>
using namespace std;
class Date
{
public:
Date(int year = 1900,int month = 1,int day = 1)
{
_year = year;
_month = month;
_day = day;
cout<<"Date"<<endl;
}
void Print()
{
cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d;
d.Print();
Date d1(2018,3,25);
d1.Print();
system("pause");
return 0;
}
全缺省的构造函数,如果在创建对象时不传任何参数,那么在调用构造函数时就会调用构造函数进行初始化,并不会生成随机值。而当我们传了参数时,就会调用我们自己传的参数。所以,一般建议在写构造函数时采用全缺省的构造函数。当类中有自定义的类时,调用缺省的构造函数并不是什么都不做。②半缺省的构造函数
#include <iostream>
#include<windows.h>
using namespace std;
class Date
{
public:
Date(int year = 1900,int month = 1)
c988
{
_year = year;
_month = month;
_day = 1;
cout<<"Date"<<endl;
}
void Print()
{
cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d;
d.Print();
Date d1(2018,3);
d1.Print();
system("pause");
return 0;
}
半缺省的构造函数,缺省参数怎么缺省(从右向左进行缺省),我在前面的博客中有介绍。。。。。。深入探索构造函数:        在C++中,使用初始化列表也可以初始化对象,而且比构造函数更高效。(因为初始化列表无论写不写,系统都会调用)用法:以冒号开始,以逗号分隔,括号里面是要初始化的值。有些变量必须在初始化列表中进行初始化:①自定义类型的类如果没有缺省的构造函数,必须在初始化列表初始化。②引用类型的成员变量。③常量。注意:初始化列表按声明的顺序进行初始化。

二,析构函数

作用:析构函数的作用刚好和构造函数的功能相反,它的作用是:在一个对象的生命周期结束时,用析构函数进行清理一些东西。析构函数的特点与构造函数很相似。#include <iostream>#include<windows.h>using namespace std;class Date{public:Date(int year = 1900,int month = 1,int day = 1){_year = year;_month = month;_day = day;cout<<"Date"<<endl;}~Date(){cout<<"~Date"<<endl;}void Print(){cout<<_year<<"-"<<_month<<"-"<<_day<<endl;}private:int _year;int _month;int _day;};int main(){Date d;d.Print();system("pause");return 0;}在VS2010中运行结果中并不会看到析构函数被调用(可能是被优化了),上面的截图是在Linux中运行的结果。我们可以看到,在函数调用完成后,就会调用析构函数进行清理工作(清理一些在堆上开辟的空间,想这样普通的函数在函数执行完后就会自动释放内存,并不需要去清理)。

三,拷贝构造函数

定义:创建对象时用同类对象来进行初始化,用一个已知的对象来创造一个新的对象。格式:<类名>::<拷贝构造函数名>(<类名>&<引用名>){    <函数体>}特点:①拷贝构造其实是构造函数的重载;②拷贝构造函数在传参时必须使用引用,如果使用传值的方式,就会引发无穷递归。③如果没有写拷贝构造函数,系统会自动生成一个缺省的拷贝构造函数。
#include <iostream>
#include<windows.h>
using namespace std;
class Date
{
public:
Date(int year = 1900,int month = 1,int day = 1)
{
_year = year;
_month = month;
_day = day;
cout<<"Date"<<endl;
}
~Date()
{
cout<<"~Date"<<endl;
}
Date(Date& d)
{
_year =d._year;
_month =d._month;
_day = d._day;
cout<<"Date&"<<endl;
}
void Print()
{
cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d(2018,3,25);
d.Print();
Date d1(d);
d1.Print();
system("pause");
return 0;
}
当我们不写拷贝构造函数时,系统也会自动生成一个拷贝构造。而且在上面的这个事例中,系统自动生成的拷贝构造函数也可以完成同样的拷贝。缺省的拷贝构造函数,会依次拷贝成员进行初始化。
#include<iostream>
#include<windows.h>
using namespace std;
class SeqList
{
public:
SeqList(const size_t capacity = 0)
{
if(capacity > 0)
{
data = (int*)malloc(sizeof(int)*capacity);
_size = 0;
_capacity = capacity;
}
else
{
data = NULL;
_size = 0;
_capacity = capacity;
}
}
~SeqList()
{
if(data)
free(data);
_size = 0;
_capacity = 0;
}
private:
int* data;
size_t _size;
size_t _capacity;
};
int main()
{
SeqList L(100);
SeqList L1(L);
system("pause");
return 0;
}
就像这个顺序表的拷贝构造,就会存在问题。而且,当对象的生命周期结束时,就会调用它的析构函数进行清理,但是我们使用了拷贝构造创建了L1对象,而且两个指向同一块空间,当一块空间被清理2次时,程序就会崩溃。

四,运算符重载

作用:提高代码的可读性。特点:函数名为:operator+合法的运算符。C++不能重载的5个运算符:.*/::/sizeof/?:/.注意:运算符重载也不可以改变运算符的优先性。。。在后面的日期类会有详细的例子。

五,const成员函数

用const修饰的对象,必须用const修饰的函数实例化。而非const修饰的函数,有const和非const实例化的函数都可以用。因为权限只能缩小,不能放大。#include <iostream>#include<windows.h>using namespace std;class Date{public:Date(int year = 1900,int month = 1,int day = 1):_year(year),_month(month),_day(day){}void Print(){cout<<_year<<"-"<<_month<<"-"<<_day<<endl;}    void Print() const //void Print(const Date* this){cout<<_year<<"-"<<_month<<"-"<<_day<<endl;}private:int _year;int _month;int _day;};int main(){Date d(2018,3,25);d.Print();const Date d1(2018,4,3);d1.Print();system("pause");return 0;}上面用const修饰的对象,必须用const修饰的函数去实现。日期类的代码就充分利用了这几个成员函数,下面是我实现的日期类的函数:
#pragma once

class Date
{
public:
Date(int year = 1900 ,int month = 1 ,int day = 1 )
:_year (year)
,_month (month)
,_day (day)
{}
bool IsInvalid();
int GetCorrectDay(int _year,int _month);
bool IsLeapYear(int _year)
{
return ((_year % 4 == 0 && _year % 100 != 0) || _year % 400 == 0);
}
void Print();
Date& operator=(const Date& d);
bool operator<(const Date& d);
bool operator==(const Date& d);
bool operator!=(const Date& d);
bool operator<=(const Date& d);
bool operator>(const Date& d);
bool operator>=(const Date& d);
Date operator++(int);   //后置++
Date& operator++();     //前置++(默认是)
Date operator--(int);
Date& operator--();
Date operator+(const int day);
Date& operator+=(const int day);
Date operator-(const int day);
Date& operator-=(const int day);
int operator-(Date& d);
private:
int _year;
int _month;
int _day;
};
#include <iostream>
using namespace std;
#include"Date.h"
bool Date::IsInvalid()
{
if(this->_year < 0 || this->_month < 0 || this->_month > 13 || this->_day < 0 || this ->_day > GetCorrectDay(this->_year,this->_month))
{
return false;
}
return true;
}
int Date::GetCorrectDay(int year,int month)
{
int m_day = 0;
int day[13] = {-1,31,28,31,30,31,30,31,31,30,31,30,31};
if(month == 2 && IsLeapYear(year))
{
m_day = 29;
}
else
{
m_day = day[month];
}
return m_day;
}
void Date::Print()
{
cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
}
Date& Date::operator=(const Date& d)
{
_year = d._year ;
_month = d._month ;
_day = d._day ;
return *this;
}
bool Date::operator<(const Date& d)
{
if(_year < d._year || (_year == d._year && _month < d._month) || (_year == d._year && _month == d._month && _day < d._day ))
{
return true;
}
return false;
}
bool Date::operator==(const Date& d)
{
if(_year == d._year && _month == d._month && _day == d._day)
{
return true;
}
return false;
}
bool Date::operator!=(const Date& d)
{
if((*this == d) == false)
{
return true;
}
return false;
}
bool Date::operator<=(const Date& d)
{
if(*this < d || *this == d)
{
return true;
}
return false;
}
bool Date::operator>(const Date& d)
{
if(!(*this < d) && !(*this == d))
{
return true;
}
return false;
}
bool Date::operator>=(const Date& d)
{
if((*this > d) || (*this == d))
{
return true;
}
return false;
}
Date Date::operator+(const int day)
{
if(day < 0)
{
return (*this - (-day));
}
Date tmp(*this);
tmp._day  += day;
while(tmp.IsInvalid() == false)
{
if(tmp._month > 12)
{
tmp. _year += 1;
tmp._month = 1;
}
int m_day = GetCorrectDay(tmp._year,tmp._month);
tmp._day -= m_day;
++tmp._month;
}
return tmp;
}
Date& Date::operator+=(const int day)
{
*this = *this + day;
return *this;
}
Date Date::operator-(const int day)
{
if(day < 0)
{
return (*this + (-day));
}
Date tmp(*this);
tmp._day -= day;
while(tmp.IsInvalid() == false )
{
if(tmp._month <= 1)
{
tmp._month = 12;
tmp._year -= 1;
}
int m_day = GetCorrectDay(tmp._year,tmp._month - 1);
tmp._day -= m_day;
--tmp._month;
}
return tmp;
}
Date& Date::operator-=(const int day)
{
*this = *this - day;
return *this;
}
Date Date::operator++(int)
{
Date tmp(*this);
*this += 1;
return tmp;
}
Date& Date::operator++()
{
*this += 1;
return *this;
}
Date Date::operator--(int)
{
Date tmp(*this);
*this -= 1;
return tmp;
}
Date& Date::operator--()
{
*this -= 1;
return *this;
}
int Date::operator-(Date& d)
{
int count = 0;
while(*this != d)
{
if(*this > d)
{
++d;
++count;
}
else if(*this < d)
{
++(*this);
++count;
}
}
return count;
}
int main()
{
Date d(2018,3,27);
Date d1(2018,3,3);
cout<<(d == d1)<<endl;
cout<<(d < d1)<<endl;
cout<<(d <= d1)<<endl;
cout<<(d > d1)<<endl;
cout<<(d >= d1)<<endl;
cout<<(d1 - d)<<endl;
d = d + 430;
d.Print();
--d;
d.Print();
d++;
d.Print();
d--;
d.Print();
d = d + 2;
d1 = d1 + 30;
d.Print();
d1.Print();
return 0;
}
日期类的代码都是在Linux中实现的。。。。。。。。。。。。

                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐