构造函数是特殊的成员函数
全局对象的构造优于main函数
Test.h:
#ifndef _TEST_H
#define _TEST_H
class Test
{
//如果类不提供任何一个构造函数,系统将为我门提供一个默认构造函数
//当类中有一个构造函数,系统不必提供默认构造函数
public:
Test();
Test(int num_);
void Display();
private:
int num;
public:
~Test();
//析构函数不能重载
};
Test.cpp:
#include "Test.h"
#include <iostream>
using namespace std;
//不带参数的构造函数称为默认构造函数
Test::Test()
{
num = 0;
cout << "Initializing Default" << endl;
}
void Test::Display()
{
cout << num << endl;
}
Test::Test(int num_)
{
num = num_;
cout << num << endl;
}
Test::~Test()
{
cout << "Destory" << num << endl;
}
02.cpp:
#include "Test.h"
#include <iostream>
using namespace std;
//全局对象的构造要优于main函数的构造
//Test t(10);
/*
int main()
{
cout << "Entering main ...." << endl;
cout << "exiting main" << endl;
return 0;
}
*/
栈中创建的对象,在生存期结束时会自动调用析构函数
堆上创建的对象,必须要程序员显示调用delete释放该对象
#include "Test.h"
/*
int main()
{
Test t[2] = {10 , 20};
Test *t2 = new Test(2);
delete t2;
Test* t3 = new Test[2];//调用默认构造函数
delete[] t3;//删除数组必须要使用的delete[]
return 0;
}
*/
#include "Test.h"
int main()
{
Test t;
// t.Test(3);
t.~Test(); //析构函数可以被显示调用,构造函数不可以
return 0;
}
转换构造函数
单个参数的构造函数
类型转换(将其他类型转换为类类型)
只有一个参数的构造函数是危险的:因为编译器可以使用这种构造函数把参数的类型隐式转换为类类型。
Test.h:
#ifndef _TEST_H
#define _TEST_H
class Test
{
//如果类不提供任何一个构造函数,系统将为我门提供一个默认构造函数
//当类中有一个构造函数,系统不必提供默认构造函数
public:
Test();
explicit Test(int num_);
void Display();
Test& operator=(const Test& other);
private:
int num;
public:
~Test();
//析构函数不能重载
};
#endif
Test.cpp:
#include "Test.h"
#include <iostream>
using namespace std;
//不带参数的构造函数称为默认构造函数
Test::Test()
{
num = 0;
cout << "Initializing Default" << endl;
}
void Test::Display()
{
cout << num << endl;
}
Test::Test(int num_)
{
num = num_;
cout << num << endl;
}
Test::~Test()
{
cout << "Destory" << num << endl;
}
Test& Test::operator=(const Test& other)
{
num = other.num;
cout << "运算符" << endl;
return *this;
}
#include "Test.h"
int main()
{
//Test t;
Test t(10); //此时并不是转换构造函数,只是普通构造函数功能
t = 20;//要将20 这个整数赋值给t对象
//1、调用装换构造函数将20这个整数转换为类类型(生成一个临时对象)
//2、静临时对象赋值给t对象(调用=运算符)
//Test t2;
return 0;
}
赋值与初始化的区别:
例如:
#include "Test.h"
int main()
{
Test t = 10;
//初始化语句中=不是赋值运算符而是等价于Test t(10)
t = 20;//赋值操作
Test t2;
t = t2;//赋值操作
return 0;
}
explicit
只提供给类的构造函数使用的关键字
编译器不会把声明explicit的构造函数用于隐式转换,他只能在程序代码中显示创建对象。
构造函数初始化列表
推荐在构造函数初始化列表进行数据初始化
构造函数执行的两个阶段
数据成员初始化
普通计算
对象成员及其初始化
const成员、引用成员初始化
const成员的初始化只能在构造函数的初始化列表中初始化
引用成员的初始化只能在构造函数的初始化列表中初始化
对象成员(如无默认构造函数)的初始化只能在构造函数的初始化列表中初始化
Clock.h:
#ifndef _CLOCK_H_
#define _CLOCK_H_
class Clock
{
public:
Clock(int hour = 0, int minute = 0 , int second = 0);
~Clock();
public:
void Display();
void Update();
void Init(int hour , int minute , int second);
public:
int hour_,minute_,second_;
};
#endif // _CLOCK_H_
--------------------------------------------------------------------------------
Clock.cpp:
#include "Clock.h"
#include <iostream>
using namespace std;
Clock::Clock(int hour , int minute , int second ) : hour_(hour),minute_(minute),second_(second)
{
/*
hour_ = hour;
minute_ = minute;
second_ = second;
*/
}
Clock::~Clock()
{
cout << "Clock::~Clock" << endl;
}
void Clock::Display(){
cout << hour_ << ":" << minute_ << ":" << second_ << endl;
}
void Clock::Init(int hour , int minute , int second)
{
hour_ = hour;
minute_ = minute;
second_ = second;
}
void Clock::Update()
{
if(second_ == 60){
minute_ ++;
second_ = 0;
}
if(minute_ == 60){
hour_ ++;
minute_ = 0;
}
if(hour_ == 24){
hour_ = 0;
}
}
--------------------------------------------------------------------------------
02.cpp:
#include <iostream>
using namespace std;
class Object
{
public:
Object(int num_):num(num_)
{
cout << "Object" << num << endl;
}
Object()
{
cout << "Object" << endl;
}
~Object()
{
cout << "~Object" << num << endl;
}
private:
int num;
};
class Container
{
public:
Container(int obj1 = 0 , int obj2 = 0 ) : obj2(obj2),obj(obj1)
//初始化顺序与初始化列表参数顺序无关,而与成员顺序有关
{
cout << "Container" << endl;
}
~Container()
{
cout << "~Container" << endl;
}
private:
Object obj;
Object obj2;
};
int main()
{
Container c(10 , 20);
return 0;
}
枚举常量对于任何对象都是确定的值
enum E_TYPE
{
TYPE_A = 100,
TYPE_B = 200
};
例如:
#include <iostream>
using namespace std;
class Object
{
public:
//枚举常量对于任何对象都是确定的值
enum E_TYPE
{
TYPE_A = 100,
TYPE_B = 200
};
public:
Object(int num_ = 0):num(num_),kNum(50),zefNum(num_)
//const 成员的初始化只能在构造函数的初始化列表中初始化
//引用成员的初始化只能在构造函数的初始化列表中初始化
//对象成员(如无默认构造函数)的初始化只能在构造函数的初始化列表中初始化
{
//kNum = 100;
cout << "Object" << num << endl;
}
~Object()
{
cout << "~Object" << num << endl;
}
void Display()
{
cout << kNum << endl;
}
private:
int num;
const int kNum ;
int& zefNum;
};
int main()
{
Object obj1(10);
Object obj2(20);
obj1.Display();
obj2.Display();
cout << Object::TYPE_A << endl;
cout << obj1.TYPE_A << endl;
cout << obj2.TYPE_A << endl;
return 0;
}
拷贝构造函数:使用一个为已经存在的对象初始化一个新的同一类型的对象。
声明:只有一个参数并且参数为该类对象的引用。
如果类中没有说明拷贝构造函数,则系统自动生成一个缺省复制构造函数,作为该类的共有成员。
例如:
test.h:
#ifndef _TEST_H
#define _TEST_H
class Test
{
//如果类不提供任何一个构造函数,系统将为我门提供一个默认构造函数
//当类中有一个构造函数,系统不必提供默认构造函数
public:
Test();
Test(const Test& t);
explicit Test(int num_);
void Display();
Test& operator=(const Test& other);
private:
int num;
public:
~Test();
//析构函数不能重载
};
#endif
test.cpp:
#include "Test.h"
#include <iostream>
using namespace std;
//不带参数的构造函数称为默认构造函数
Test::Test():num(0)
{
//num = 0;
cout << "Initializing Default" << endl;
}
Test::Test(const Test& t):num(t.num)
{
//参数必须是Const Test&,如果那么做则会产生递归产生对象
cout << "拷贝构造函数" << num << endl;
}
void Test::Display()
{
cout << num << endl;
}
Test::Test(int num_)
{
num = num_;
cout << "初始化" << num << endl;
}
Test::~Test()
{
cout << "Destory" << num << endl;
}
Test& Test::operator=(const Test& other)
{
num = other.num;
cout << "运算符" << endl;
return *this;
}
01.cpp:
#include "Test.h"
int main()
{
Test t(20);
//Test t2(t); //调用拷贝构造函数
//如果类中没有说明拷贝构造函数,则系统自动生成一个缺省复制构造函数,作为该类的共有成员
Test t2 = t;
return 0;
}
拷贝构造函数调用的几种情况
当函数的形参是类的对象,调用函数时,进行形参与实参结合时使用。这时要在内存新建立一个局部对象,并把实参拷贝到新的对象中。理所当然也调用拷贝构造函数。
当函数的返回值是类对象,函数执行完成返回调用者时使用。理由也是要建立一个临时对象中,再返回调用者。为什么不直接用要返回的局部对象呢?因为局部对象在离开建立它的函数时就消亡了,不可能在返回调用函数后继续生存,所以在处理这种情况时,编译系统会在调用函数的表达式中创建一个无名临时对象,该临时对象的生存周期只在函数调用处的表达式中。所谓return 对象,实际上是调用拷贝构造函数把该对象的值拷入临时对象。如果返回的是变量,处理过程类似,只是不调用构造函数。
例如:
02.cpp:
#include "Test.h"
void TestFun(const Test other)
{
}
void TestFun2(const Test& other)
{
//建议引用,可以减少内存创建
}
Test TestFun3(const Test& other)
{
return other ;
}
const Test& TestFun4(const Test& other)
{
return other ;
}
int main()
{
int a = 3;
int& b = a;
Test t(20);
//TestFun(t);
//TestFun2(t);
//TestFun3(t);
Test t2 = TestFun3(t);
Test& t3 = TestFun3(t);
Test t4 = TestFun4(t);
const Test& t5 = TestFun4(t);
return 0;
}