類的六大預設建構函式
阿新 • • 發佈:2019-01-05
預設的建構函式和解構函式,等於放棄了自己初始化和清除的機會;預設的拷貝構造和預設的賦值函式,採用“位拷貝和值拷貝”。若類中出現指標時,這兩個函數出錯。
class String
{
public:
String(const char *str = NULL);//構造
~String();//析構
String (const String &s);//拷貝構造
String& operator=(const String &s);//賦值
String* operator&();//普通引用方法
String* operator&()const;//常引用方法
private :
char* m_str;
};
建構函式與解構函式
建構函式和解構函式表明了一個物件的由生到死的過程。一個物件只能呼叫一次構造方法,一個類有且只有一個析構方法。
建構函式作用:
1、例項化物件 2、對物件成員進行初始化 3、強制型別轉化(通過中間橋樑實現)
#
類的資料成員的初始化方式(二者效率不同)
1、初始化列表方式
2、函式體內賦值
3、類的const 常量只能在初始化列表內初始化,不能在函式體內進行賦值。
#
構造順序
1、遇到物件自動呼叫其構造方法,如若有繼承關係時,則先呼叫父類的構造方法;當主函式中構造物件完成時自動呼叫解構函式。
2、先構造者後析構,因為建構函式中,物件是通過堆疊的方式進行儲存的,同理 析構時按照出棧的順序。
成員物件初始化的次序完全不受他們在初始化列表中的次序,只與成員物件在類中的宣告次序有關。
#include<iostream>
using namespace std;
class Test
{
public:
Test()
{
cout<<this<<endl;//6c
}
Test(int d,int num):number(num),data(d)
{
cout<<this<<endl;//64
cout<<"data-->" <<this->data<<endl;
cout<<"number-->"<<this->number<<endl;
}
~Test()
{
cout<<"~Test()"<<this<<endl;
}
private:
int data;
int number;
};
void main()
{
Test t;
Test t2(1,2);
}
強制型別轉化
#include<iostream>
using namespace std;
class Test
{
public:
Test()
{
cout<<"Test()"<<this<<endl;
}
Test(int d):data(d)
{
cout<<"Test()"<<this->data<<endl;
}
/*int GetData()const
{
return data;
}
*/
operator int()
{
return data;
}
~Test()
{
cout<<"Free Test()"<<this<<endl;
}
private:
int data;
};
void main()
{
//Test t1(); 宣告函式,能編譯、能執行,但是是錯誤的
Test t(1);
t =100;//100通過構建函式構造中間零時物件,物件給物件賦值
//若建構函式前面加上explicit關鍵字時,則賦值時必須顯示呼叫即 t =(Test) 100;
int value;
//通過公有方法獲取data值
//value = t.GetData();
//呼叫operator int()方法,將物件型別強制轉換為值型別
value = t;
}
建構函式,有兩種方式:
1、定義無參建構函式 2、定義所用帶預設值的建構函式 且 二者方式只能用一種。一個類只能有一個帶預設值的建構函式。不然程式產生二義性。當帶預設值的引數,沒有初始化時,則產生隨機值。
#include<iostream>
using namespace std;
class Test
{
public:
//無參構造
Test()
{}
Test(int d):data(d)
{
cout<<data<<endl;
}
//帶預設值的構造
/*
Test(int d=0)
{
data = d;
cout<<data<<endl;
}
*/
private:
int data;
};
void main()
{
Test t(2);
}
拷貝構造與賦值函式
拷貝建構函式:用一個已有物件去初始化一個新的物件。
產生拷貝構造的條件:
1、用已有物件去初始化新的物件
2、函式引數型別傳遞
3、函式返回值型別的物件。
include<iostream>
using namespace std;
include<vld.h>
class Test
{
public:
Test()
{}
Test(int d):data(d)
{}
void print()
{
cout<<data<<endl;
}
//不用引用,自己解釋自己會產生迴圈遞迴
Test(const Test &other)
{
data = other.data;
}
~Test()
{
cout<<"~Test()"<<endl;
}
private:
int data;
};
void fun(Test s1)
{
cout<<"fun()"<<endl;
}
Test fn()
{
Test s2(1);
//返回s2之前會產生無名的臨時物件,即用s2去構造物件 因此呼叫拷貝建構函式
return s2;
}
void main()
{
Test t(2);
//兩者一樣
//Test t1(t);
Test t1= t;
t.print();
t1.print();
//物件作為函式引數
fun(t1);
//物件作為函式的返回值
t=fn();
}
return 返回時,實際呼叫了拷貝建構函式構造了一個無名的臨時物件
int Sum(int a,int b)
{
return sum=a+b;
//返回的不是sum,sum在離開作用域時,已經被釋放;會產生一個臨時無名物件,並將sum 值傳給該物件。
}
void main()
{
int val=Sum(1,2);
}
賦值
賦值相當於a物件的成員引數,給b的成員引數賦值。
1、是否把返回值的型別宣告為該型別的引用。
2、是否把傳入的引數宣告為常量引用。
3、是否釋放自己已有空間。
4、是否判斷傳入的引數和當前的例項(*this)是不是一個例項。
#
#include<iostream>
using namespace std;
#include<vld.h>
class Test
{
public:
Test(int d=0):data(d)
{}
void print()
{
cout<<data<<endl;
}
Test(const Test &other)
{
data = other.data;
}
/*
1.const:表明物件的資料成員在賦值過程中,不被修改
2.&s:減少呼叫一次拷貝建構函式,也提高效率,在程式中,當物件不受函式作用域的影響時,可以使用&
3.Test 為了是連續物件間賦值t1=t2=t3;
4.在返回類的物件*this時,會產生臨時物件呼叫拷貝建構函式。&為了不構造臨時物件,減少呼叫拷貝構造
t1.operator=(t2.operator=(t3))
*/
Test& operator=( const Test &s)
{
if(this != &s)
{
data = s.data;
}
//返回當前物件
return *this;
}
~Test()
{
cout<<"~Test()"<<endl;
}
private:
int data;
};
void main()
{
Test t(10);
Test t1(t);
Test t2;
t2 = t1;
//t2.operator=(t1)
//t2.operator=(&t2,t1)
//下面的const用來說明當前物件不允許修改
//Test& operator(Test *const this,const Test &s )
}
普通引用方法與常引用方法
#include<iostream>
using namespace std;
#include<vld.h>
class String
{
public:
String(char *str=NULL)
{
//構造的物件為NULL時,String a(""|NULL|0)和String a()不一樣
if(str == NULL)
{
m_str = new char[1];
*m_str = '\0';
}
else
{
m_str = new char[strlen(str)+1];
strcpy(m_str,str);
}
}
//深拷貝
String(const String &s)
{
m_str = new char[strlen(s.m_str)+1];
strcpy(m_str,s.m_str);
}
//深賦值
String& operator=(const String &other)
{
if(this != &other)
{
String tmp=other;
char *pstr=m_str;
m_str= tmp.m_str;
tmp.m_str = pstr;
}
return *this;
}
//普通引用方法
String* operator&()
{
return this;
}
//常方法
const String* operator&()const
{
return this;
}
~String()
{
delete []m_str;
m_str = NULL;
}
private:
char *m_str;
};
void main()
{
String s("123");
String s1=s;
String s2;
s2=s1;
String *p =&s1;
const String s3("Hello");
const String *q =&s3;
}