C++之賦值函數和析構函數


析構函數

自動調用-------跟 構造函數相近


析構函數 
特點1:對象消失的時候自動調用
特點2:函數名----類名 相同;前邊加~
特點3:系統有默認的析構函數(但它什麼都不幹)-------當有成員變量是動態內存分配時,就必須重寫析構函數
特點4:函數原型永遠就1個




//代碼:
//main.cpp


#include <iostream>
#include <iomanip>
#include <string.h>
#include <stdlib.h>
#include "Student.h"
using namespace std;


int main()
{
	CStudent stu1(1001,"zhangsan");
	//stu1.free_name();				//如果沒有析構函數,我


們就必須自己定義1個函數,來釋放name;並手動來執行。----用了析構只是方便了


	return 0;
}




//Student.cpp中完善 析構函數
CStudent::~CStudent()
{
	free(name);
	cout<<"析構函數運行了"<<endl;
}




如果使用new來建立 對象,就必須使用delete來釋放對象------此時析構函數纔會被調用


如果使用new來建立 對象,就必須使用delete來釋放對象------否則,析構函數不會被調

//用代碼:
int main()
{
	//CStudent stu1(1001,"zhangsan");
	//stu1.free_name();


	CStudent *pstu=new CStudent(1001,"zhangsan");
	delete pstu;


	return 0;
}


賦值函數

特點1:系統有默認的 賦值函數------一般不能用(因爲簡單的賦值語句,在使用char * name時,會是淺複製)
特點2:所以一般要重寫
特點3:------不是構造函數(定義變量時調用)



//代碼:
//main.cpp
int main()
{
	CStudent stu1(1001,"zhangsan");
	CStudent stu2(1002,"lisi");
	stu2=stu1;//stu2.fun(stu1);		//二者幾乎等價,所以,我們先來


//定義1個成員函數 fun,實現nummber和name的複製
	stu2.print_student();


	return 0;
}



賦值函數的書寫步驟:
先寫fun函數,驗證通過後-------將fun替換爲operator=----------------main


函數中,直接改爲stu2=stu1;



//main.cpp
int main()
{
	CStudent stu1(1009,"zhangsan");
	CStudent stu2(1002,"lisi");
	//stu2=stu1;//stu2.fun(stu1);		//二者幾乎等價,所以,我們先來


//定義1個成員函數 fun,實現nummber和name的複製
	//stu2.operator=(stu1);//fun-----   operator=
	stu2=stu1;
	stu2.print_student();
	return 0;
}


//Student.h
	void operator=(CStudent &stu1);
	
//Student.cpp
void CStudent::operator=(CStudent &stu1)
{
	number=stu1.number;
	//name=stu1.name;
	name=(char *)malloc(strlen(stu1.name)+1);
	strcpy(name,stu1.name);
	return;
}

	
//進一步完善 賦值函數:
//原因:自己給自己賦值    -----應直接返回;否則,程序會崩潰
//main.cpp
int main()
{
	CStudent stu1(1009,"zhangsan");
	CStudent stu2(1002,"lisi");
	//stu2=stu1;//stu2.fun(stu1);		//二者幾乎等價,所以,我們先來


定義1個成員函數 fun,實現nummber和name的複製
	//stu2.operator=(stu1);//fun-----   operator=
	//stu2=stu1;
	stu2=stu2;				//自己給自己賦值----可能會有問


題
	stu2.print_student();
	return 0;
}


void CStudent::operator=(CStudent &stu1)
{
	if(&stu1==this)
	{
		return;
	}
	number=stu1.number;
	//name=stu1.name;
	name=(char *)malloc(strlen(stu1.name)+1);
	strcpy(name,stu1.name);
	return;
}


//進一步完善 賦值函數:
//原因:鏈式傳送的需求,所以要有返回值


//main.cpp
int main()
{
	CStudent stu1(1009,"zhangsan");
	CStudent stu2(1002,"lisi");
	CStudent stu3(1003,"wangwu");
	stu3=stu2=stu1;
	stu1.print_student();
	stu2.print_student();
	stu3.print_student();
	return 0;
}




//Student.cpp
CStudent &CStudent::operator=(CStudent &stu1)
{
	if(&stu1==this)
	{
		return *this;
	}
	number=stu1.number;
	//name=stu1.name;
	name=(char *)malloc(strlen(stu1.name)+1);
	strcpy(name,stu1.name);
	return *this;
}



//給name賦值的代碼解析:
//代碼1:
int main()
{
	char *name=new char[10];
	name="abcd";
	cout<<name;
	return 0;
}
//注意:10個內存空間根本沒有使用;而且存它的首地址的變量name,被修改後,這10個內


//存空間也永遠不會被delete掉,發生了內存泄露
//但輸出結果 正常


代碼2:
int main()
{
	char *name=new char[10];
	//name="abcd";
	strcpy(name,"abcd");
	cout<<name;
	return 0;
}
//注意:是深複製。將另外1個字符串"abcd",複製了1份,存到了10個字節的內存空間中(當然只佔了前5個字節的空間)
//輸出結果   也正常


name    ----382c90
        ----43201c   name被改成 該地址


	




int main()
{
	//char name[10]="abcd";  這行語句等價於下面的語句。  =不是純粹的賦值   


 ----因爲它在定義變量


	char name[10];
	name[0]='a';    //=是純粹的賦值,要求2邊數據類型要一致--------因爲前面


沒有 數據類型,說明不是在定義變量
	name[1]='b';
	return 0;
}


////////////////////////////////////////////////////////////
int main()
{
	//char name[10]="abcd";
	char *name=new char[10];
	strcpy(name,"abcd");


	char *name2=name;   //這種用法很危險,如下
	delete name;		//釋放name,也相等於 同時釋放name2----因爲大家指向了同一內存空間

	delete name2;


	return 0;
}



//進一步完善賦值函數-------name被重新賦值了(使用malloc),而以前name裏有"lisi",結果以後再也釋放不了了

CStudent &CStudent::fun(CStudent &stu1)
{
	if(&stu1==this)
	{
		return *this;
	}
	number=stu1.number;
	//name=stu1.name;
	free(name);
	name=(char *)malloc(strlen(stu1.name)+1);
	strcpy(name,stu1.name);
	return *this;
}


//賦值函數再改進--------考慮到malloc可能會分配失敗。
CStudent &CStudent::fun(CStudent &stu1)
{
	if(&stu1==this)
	{
		return *this;
	}
	number=stu1.number;
	//name=stu1.name;
	//free(name);
	char *name_bak=name;
	name_bak=(char *)malloc(strlen(stu1.name)+1);
	if(name_bak==NULL)
	{
		return *this;
	}
	free(name);
	name=name_bak;
	strcpy(name,stu1.name);
	return *this;
}





1、自定義1個CStudent類,包含學號、姓名、語文成績、英語成績。編寫4大成員函數。要求使用new/delete cin/cout。在main函數中,建立1個學生數組(可以放3個元素),通過鍵盤輸入學生信息,並打印信息。


2、自定義1個鏈表類,然後在main函數中,建立1個鏈表對象,然後通過鏈表的成員函數,進行3個學生信息,加入到鏈表中,最後,遍歷打印學生信息。


//思路:
#include <iostream>
#include <stdlib.h>
#include <string.h>


//void (*printf_student)(void *data);


class CStudent
{


};




void printf_student(void *data)
{




	return;
}



int main()
{
	CStudent stu1(1001,"zhangsan");
	CLink link;
	link.add_node((void *)&stu1);
	link.foreach(printf_student);
	link.destroy(delete_name);
	//link_create();


	return 0;
}



知識點:
鏈表函數庫------->封裝成CLink類-----》main函數不是 成員函數----只能通過給工程 新建文件 來完成在main函數裏,有1條 語句-----建立1個學生,而且還賦值爲 1001 "zhangsan"這裏出現了 新的 數據類型 CStudnt-----分清它屬於 那個模塊     ----很具體的1個數據類型,應該屬於應用層  頂層
雖然 也屬於 頂層,但CStudent如果放置在自己的 .h  .cpp  更好所以,該頂層 將有  3個文件在main函數裏,有1條 語句-----建立 空鏈表      CList list;
這裏出現了 新的 數據類型 CList-----分清它屬於 那個模塊      -----很抽象,應該屬於 底下1層既然是 地下1層,就要求 該類型的 成員變量、參數------不能有頂層的 數據類型----不能有CStudent,CList list 其實等價於 調用了1個 無參構造函數該函數的功能:應該是 給自己的 成員變量head,賦值,而且爲NULL

在main函數裏,有1條 語句-----給鏈表裏 增加 節點可以考慮用CList的成員函數來實現

該CList的成員函數,可以直接調用 link.h/link.cpp中的 link_add_node()函


數來實現
考慮到 link_add_node()  是再下1層的   
 
該函數裏要 先建立1個 CNode節點  
考慮 CNode節點    應爲 底下1層
CNode  也通過.h  .cpp來寫層:由高 到低



main.cpp
Student.h、Student.cpp

List.h/List.cpp

link.h/link.cpp    pfun數據類型

Node.h/Node.cpp




如何 添加頭文件:
原則:
始終都是  上層 調用 下層
調用時,使用下1層的函數-----使用前要加 下1層的函數原型-------用include .h 省事


實現


//1 類間的關係
//組合	-----   組裝         學生----成績
//聚合	-----   聚集         主窗口-----  子窗口


//組合 的使用:
//給學生類  裏  放1個  成績
//成績-----變量     特殊的變量(類)

//在定義 學生的構造函數時,如何給 chengji變量 賦值?
	//利用 CScore的構造函數 來給 chengji 賦值。
	//引出了  初始化表-------  :chengji(chinese,math,englis)   放置在 函數原型後面(cpp中的,.h不用變)

CStudent::CStudent(int number,char *name,int chinese,int math,int english):chengji(chinese,math,english)//初始化表
{
	this->number=number;
	this->name=new char[strlen(name)+1];
	strcpy(this->name,name);
	//this->chinese=chinese;
	//this->math=math;
	//this->english=english;
	//chengji.CScore(chinese,math,english);   因爲CScore()是構造函數,不能這麼用
}	


//小技巧:
//調用CStudent的print函數時,可以調用 CScore的print函數

//組合代碼:
//main.cpp

#include "Student.h"

int main()
{
	CStudent stu1(1001,"zhangsan",61,62,63);
	stu1.print_student();

	return 0;
}


//Student.h
// Student.h: interface for the CStudent class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_STUDENT_H__6C8339B9_6432_4E34_A210_A960F4A095CC__INCLUDED_)
#define AFX_STUDENT_H__6C8339B9_6432_4E34_A210_A960F4A095CC__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "Score.h"

class CStudent  
{
public:
	int number;
	char *name;
	//int chinese;
	//int math;
	//int english;
	CScore chengji;
	CStudent();
	virtual ~CStudent();
	CStudent(int number,char *name,int chinese,int math,int english);
	void print_student();

};

#endif // !defined(AFX_STUDENT_H__6C8339B9_6432_4E34_A210_A960F4A095CC__INCLUDED_)


//Student.cpp
// Student.cpp: implementation of the CStudent class.
//
//////////////////////////////////////////////////////////////////////
#include <iostream>
#include "Student.h"

using namespace std;
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CStudent::CStudent()
{

}

CStudent::~CStudent()
{

}

CStudent::CStudent(int number,char *name,int chinese,int math,int english):chengji(chinese,math,english)//初始化表
{
	this->number=number;
	this->name=new char[strlen(name)+1];
	strcpy(this->name,name);
	//this->chinese=chinese;
	//this->math=math;
	//this->english=english;
	//chengji.CScore(chinese,math,english);   因爲CScore()是構造函數,不能這麼用
}

void CStudent::print_student()
{
	cout<<"number is "<<number<<endl<<"name is "<<name<<endl;
	//cout<<"chines is "<<chengji.chinese
	chengji.print_chengji();
	return;
}


//Score.h
class CScore  
{
public:
	int chinese;
	int math;
	int english;
	CScore();
	CScore(int chinese,int math,int english);
	virtual ~CScore();
	void print_chengji();

};


//Score.cpp
// Score.cpp: implementation of the CScore class.
//
//////////////////////////////////////////////////////////////////////
#include <iostream>
#include "Score.h"

using namespace std;

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CScore::CScore()
{

}

CScore::~CScore()
{

}

CScore::CScore(int chinese,int math,int english)
{
	this->chinese=chinese;
	this->math=math;
	this->english=english;		
}

void CScore::print_chengji()
{
	cout<<"chinese is "<<chinese<<"  math is "<<math<<"  english is "<<english<<endl;
	return;
}


 
 
 




















發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章