类内相关非成员函数
可以直接放在类得声明与定义文件中。
//Time.h
void func();
class Time{
public:
int Hour{ 1 };
int Minute{ 4 };
const int C_Second{ 0 };
};
//Time.cpp
void func(){
return;
}
Time::Time(const int& tmp_hour, const int& tmp_minute, const int& tmp_second)
:Hour(tmp_hour), Minute(tmp_minute), C_Second(tmp_second){
}
类内初始化
在C++11中,我们可以为类内的成员变量提供一个初始值,那么我们在创建对象的时候,这个初始化值就用来初始化该成员变量。
可以在声明类内成员变量时,对成员变量赋一个初始值。
//Time.h
class Time{
public:
int Hour{ 1 };
int Minute{ 4 };
const int C_Second{ 0 };
};
//Time.cpp
Time::Time(const int& tmp_hour, const int& tmp_minute, const int& tmp_second)
:Hour(tmp_hour), Minute(tmp_minute), C_Second(tmp_second){
}
Time::Time(const int& tmp_hour, const int& tmp_minute)
:Hour(tmp_hour){ //调用这个构造函数时,因为没有初始化C_Second所以C_Second会被赋予类内初始化时的值
}
//file.cpp
#include "Time.h"
int main(){
Time mytime { 2 };
cout << mytime.Hour << endl; //2
cout << mytime.Minute << endl; //4
cout << mytime.Second << endl; //0
}
const成员变量的初始化,在构造函数的初始化列表中进行,不可以通过赋值来初始化。
默认构造函数
没有参数的构造函数,我们就称为默认构造函数
//Time.h
class Time{
public:
int Hour{ 0 };
int Minute{ 0 };
const int C_Second{ 0 };
};
//file.cpp
#include "Time.h"
int main(){
Time mytime;
cout << mytime.Hour << endl; //Hour = 0
}
没有构造函数的类对象的初始化通过默认初始化,即通过一个特殊的构造函数来执行默认初始化,这个特殊的构造函数就叫做“默认的构造函数”,也就是无参数的构造函数。
我们的类定义中没有构造函数的情况下编译器就会为我们隐式地自动定义一个构造函数(无参)。称为“合成的默认构造函数”。
合成的默认构造函数将我们在类内声明成员变量时所做的类内初始化值,赋给成员变量。
一旦我们自己写了构造函数则不管这个构造函数是否带参数,编译器都不会在我们创建“合成的默认构造函数”。
=default,=delete
//Time.h
class Time{
public:
int Hour{ 0 };
int Minute{ 0 };
const int C_Second{ 0 };
Time() = default; //编译器能够为 =default;的函数自动生成函数体: {}
};
//file.cpp
#include "Time.h"
int main(){
Time mytime;
cout << mytime.Hour << endl; //Hour = 0
}
= default; :编译器能够为 =default;的函数自动生成函数体: {}
非特殊函数不可以使用 =default;,构造函数,析构函数可用
= delete:让程序员显示的禁用某个函数。
拷贝构造函数:
默认情况下,类对象的拷贝是每个成员变量,逐个拷贝。
Time myTime;
Time myTime2 = myTime;
Time myTime3 ( myTime );
Time myTime4 { myTime };
Time myTime5 = { myTime };
如果一个类的构造函数的第一个参数是所属类的类型的引用。如果还有其它额外的参数那么这些额外的参数,那么这些额外的参数还都有默认值。则这个构造函数就叫做拷贝构造函数。
(拷贝构造函数除第一个类引用外,如果后米还有其他的参数则必须有默认值)
Time::Time(const Time &tmp, int a = 10)
函数默认参数必须放在函数声明中,除非该函数没有函数声明。
//Time.h
class Time{
public:
int Hour{ 0 };
int Minute{ 0 };
const int C_Second{ 0 };
Time(Time &tmpTime, int a = 1);
};
//Time.cpp
Time::Time(const Time &tmpTime, int a = 1){
}
//file.cpp
#include "Time.h"
int main(){
Time mytime;
Time myTime2 = myTime; //调用拷贝构造函数
Time myTime3 ( myTime ); //调用拷贝构造函数
Time myTime4 { myTime }; //调用拷贝构造函数
Time myTime5 = { myTime }; //调用拷贝构造函数
Time myTime6;
myTime6 = mytime; //没有调用拷贝构造函数
}
1、建议拷给构造函数第一个参数总是带着const
2、拷贝构造函数一般不要声明成explicit
3、成员变量逐个拷贝的功能因为我们自己定义的拷贝函数的存在儿失去了作用,或者说我们自己定义的拷贝构造函数取代了系统默认的 每个成员变量逐个拷贝 的这种行为。
如果我们没有定义拷贝构造函数,系统就会帮我们定义一个“合成拷贝构造函数”。
如果是编译器给我们合成的拷贝构造函数,一般也是将参数tmptime的成员逐个拷贝到正在创建的对象中。
每个成员的类型决定了它如何拷贝,比如说成员变量是整型的,那么就直接把它拷贝过来,如果成员变量是类类型,那么就会调用这个类的拷贝构造函数来拷贝。
如果你自己定义了拷贝构造函数,那么就取代了系统合成的拷贝构造函数,这个时候,你就必须要在你自己的拷贝构造函数中给类成员赋值。以免出现类成员没有被赋值就使用的情况发生。
还有那些情况会发生拷贝构造函数的调用情况
void func(Time tmp){
return;
}
Time mytime;
func(mytime);
//--------------------------------------------------
Time func(){
Time tmpTime;
return tmpTime;//系统产生了临时对象
}
Time time = func();
1、将一个对象作为实参传给一个非引用类型的形参。
2、从一个函数中返回一个对象的时候。
3、还有一些其他的情况也会调用拷贝构造函数。