构造函数是特殊的成员函数,需要注意的是,构造函数虽然名称叫构造,但是构造函数的主要任 务并不是开空间创建对象,而是初始化对象。
- 函数名与类名相同。
- 无返回值。(void 也不行)
- 对象实例化时编译器自动调用对应的构造函数。
- 构造函数可以重载。
class Date
{
public:
//构造函数
Date(int year ,int month , int day )
{
_year = year;
_month = month;
_day = day;
}
void Print()
{
cout << _year << "/" << _month << "/" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2023, 8, 12);
d1.Print();
}
除了上面,也可以用多种构造函数,来完成初始化
class Date
{
public:
//构造函数
Date(int year ,int month , int day )
{
_year = year;
_month = month;
_day = day;
}
//无参构造函数
Date()
{
_year = 2023;
_month = 4;
_day = 17;
}
void Print()
{
cout << _year << "/" << _month << "/" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2023, 8, 12);
d1.Print();
Date d2;
d2.Print();
}
但是当这样写的时候,就会出现问题
class Date
{
public:
//全缺省构造函数
Date(int year = 1 ,int month = 1, int day = 1 )
{
_year = year;
_month = month;
_day = day;
}
//无参构造函数
Date()
{
_year = 2023;
_month = 4;
_day = 17;
}
void Print()
{
cout << _year << "/" << _month << "/" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2023, 8, 12);
d1.Print();
Date d2;
d2.Print();
}
错误原因:对于不带参数的对象,既可以调用全缺省构造,也可以调用无参构造,但是编译器会不知道调用哪一个。
如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义编译器将不再生成。
1、无参构造(没有形参的构造函数)称之为默认构造函数
2、全缺省构造(形参都有缺省值)也称之为默认构造函数
3、编译器自动生成的默认构造函数
对于编译器自己生成的,该类中的成员变量会被初始化为随机值
class Date
{
public:
全缺省构造函数
//Date(int year = 1 ,int month = 1, int day = 1 )
//{
// _year = year;
// _month = month;
// _day = day;
//}
无参构造函数
//Date()
//{
// _year = 2023;
// _month = 4;
// _day = 17;
//}
void Print()
{
cout << _year << "/" << _month << "/" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
/*Date d1(2023, 8, 12);
d1.Print();*/
Date d2;
d2.Print();
return 0;
}
关于编译器生成的默认成员函数,很多人会有疑惑:不实现构造函数的情况下,编译器会
生成默认的构造函数。但是看起来默认构造函数又没什么用?
对象调用了编译器生成的默认构造函数,但是对象_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
{
public:
全缺省构造函数
//Date(int year = 1 ,int month = 1, int day = 1 )
//{
// _year = year;
// _month = month;
// _day = day;
//}
无参构造函数
//Date()
//{
// _year = 2023;
// _month = 4;
// _day = 17;
//}
void Print()
{
cout << _year << "/" << _month << "/" << _day << endl;
}
private:
//内置类型
int _year;
int _month;
int _day;
//自定义类型
Time _t;
};
int main()
{
/*Date d1(2023, 8, 12);
d1.Print();*/
Date d2;
d2.Print();
return 0;
}
说明:_year,_month,_day都是随机值,而Time _t这个变量是class Time自定义类型,编译器会走到Time类中,调用该类的构造函数。
typedef int STDateType;
class Stack
{
public:
Stack(size_t capacity = 4)
{
cout << "Stack()" << endl;
_array = (STDateType*)malloc(sizeof(STDateType) * capacity);
if (_array == nullptr)
{
perror("malloc fail");
return;
}
_capacity = capacity;
_size = 0;
}
void Push(STDateType x)
{
//CheckCapacity()
_array[_size++] = x;
}
//析构函数
~Stack()
{
cout << "~Stack()" << endl;
free(_array);
_array = nullptr;
_capacity = _size = 0;
}
private:
STDateType* _array;
int _capacity;
int _size;
};
class MyQueue
{
Stack _pushST;
Stack _popST;
};
int main()
{
MyQueue q;
return 0;
}
对于MyQueue来说,成员变量都为自定义类型,编译时会去调用Stack中的构造函数
析构函数与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作。
- 析构函数名是在类名前加上字符 ~。
- 无参数无返回值类型。
- 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构 函数不能重载。
- 对象生命周期结束时,C++编译系统系统自动调用析构函数。
typedef int STDateType;
class Stack
{
public:
Stack(size_t capacity = 4)
{
cout << "Stack()" << endl;
_array = (STDateType*)malloc(sizeof(STDateType) * capacity);
if (_array == nullptr)
{
perror("malloc fail");
return;
}
_capacity = capacity;
_size = 0;
}
void Push(STDateType x)
{
//CheckCapacity()
_array[_size++] = x;
}
//析构函数
~Stack()
{
cout << "~Stack()" << endl;
free(_array);
_array = nullptr;
_capacity = _size = 0;
}
private:
STDateType* _array;
int _capacity;
int _size;
};
class MyQueue
{
Stack _pushST;
Stack _popST;
};
int main()
{
Stack s;
s.Push(1);
return 0;
}
析构函数的调用是在执行return 0后,函数即将销毁时自动调用它,然后堆区空间就会被释放,且其他变量清零。
默认析构函数与默认构造函数同理,都是我们不生成时,编译器自动生成一个析构函数,但编译器生成的也只能处理一些简单类型的成员变量,例如日期类:
class Date
{
public:
//全缺省构造函数
Date(int year = 1 ,int month = 1, int day = 1 )
{
_year = year;
_month = month;
_day = day;
}
无参构造函数
//Date()
//{
// _year = 2023;
// _month = 4;
// _day = 17;
//}
void Print()
{
cout << _year << "/" << _month << "/" << _day << endl;
}
private:
//内置类型
int _year;
int _month;
int _day;
//自定义类型
Time _t;
};
int main()
{
Date d1(2023, 8, 13);
return 0;
}
对于复杂类型的成员变量,编译器自动生成的析构函数并不能完成最后的清理工作,比如:对于堆区空间的生成…所以还需要自己去写析构函数