天天看點

【C++學習】面向對象(oop)一、頭檔案與命名空間二、面向對象程式設計二、示例

文章目錄

  • 一、頭檔案與命名空間
    • 1. 頭檔案是什麼
    • 2.幾個特殊情況
    • 3.命名空間
  • 二、面向對象程式設計
    • 1.文法點
      • 1.1 private、public、protected
      • 1.2 inline
      • 1.3 const
      • 1.4 static
      • 1.5 friend
    • 2.面向對象的難點問題
      • 2.1 構造函數
      • 2.2 操作符重載問題
      • 2.3 copy問題
      • 2.4 析構函數問題
      • 2.5 值、指針、引用
        • 2.5.1 value 與 reference
        • 2.5.2 reference 與 pointer
  • 二、示例
    • 1.類不含指針(Complex)
    • 2.類含指針(String)

一、頭檔案與命名空間

1. 頭檔案是什麼

例:A.cpp, A.h, B.cpp

A.h 頭檔案 中寫入類聲明、函數原型、#define;

A.cpp實作檔案 寫入類函數的定義實作;

B.cpp調用檔案 通過一個宏指令 “#include” 調用A.h中的類和函數等

[注1] 頭檔案無需編譯,隻需在源檔案預處理時被合并

[注2]#include功能僅是簡單的文本替換

[注3]系統頭檔案用< >, 自定義頭檔案用" "

//頭檔案的防禦式程式設計
#ifndef A_H
#define A_H

//...

#endif
           

2.幾個特殊情況

(1)static修飾變量、函數可以寫在.h檔案中

(2)inline内聯函數定義可以寫在.h檔案中

(3)模闆類型可以寫在.h中,模闆在調用時才編譯

3.命名空間

區分不同庫中相同名稱的函數、類、變量

  1. 定義
namespace namespace_name {
   // 代碼聲明
}
           
  1. 調用
//後續的代碼将使用指定的命名空間中的名稱。
using namespace namespace_name;

//指定命名空間中的特定項目
using std::cout;
           

二、面向對象程式設計

1.文法點

1.1 private、public、protected

(1)資料防止洩露,通常為private。

(2)protected可由派生類通路。

(3)同一類的不同對象可以互相通路private變量、函數。

1.2 inline

(1)内聯函數的兩種寫法:

  1. 定義寫在類内
  2. 定義寫在類外,加上inline字首

(2)内聯函數隻是一種建議,具體實作由編譯器決定

(3)内聯函數減少了運作棧儲存變量的開銷

1.3 const

(1)const成員變量:不應被改變

(2)const成員函數:不應改變成員變量的值

(3)const對象:隻能通路被 const 修飾的成員函數、變量

(4)const int* p與int* const p

1.4 static

static類型屬于類,對象間共享記憶體

(1)static成員變量

(2)stattic成員函數

  1. 隻能通路靜态成員變量
  2. 聲明時加static,定義時不加static

1.5 friend

【友元函數】

(1)友元函數不是類的成員函數,在類中聲明,類外定義

(2)友元函數有權通路類的private、protected、public函數和變量。

(3)友元函數必須通過參數傳遞對象才能通路類的成員

【友元類】

(1)友元類中的所有成員函數都是另外一個類的友元函數。

2.面向對象的難點問題

2.1 構造函數

  1. 初始化問題

    complex(double r, double i):re(r),im(i) {}

    提前初始化,而不是用assign指派有利于提高性能。
  2. 構造函數可以重載
  3. private中的構造函數:單例模式

2.2 操作符重載問題

  1. 操作符重載的兩種方法

    成員函數方法:a.op(b),含有傳回值滿足連續op的情況;

    全局函數+友元函數方法:op(a,b);

  2. 不能重載的操作符

    .

    ?:

    ::

    sizeof

  3. 運算符重載不改變優先級

2.3 copy問題

  1. 深拷貝 和 淺拷貝

    淺拷貝:類内變量建立副本,類内指針共享記憶體

    深拷貝:需要自定義重載

  2. 預設拷貝為淺拷貝,含指針的類可能出現記憶體洩露
  3. 拷貝構造copy ctor 和 拷貝指派copy op=

    copy op= 等價于 自我指派檢測 + delete_self + copy ctor

2.4 析構函數問題

  1. 類記憶體在動态配置設定記憶體的情況時(往往表現為含指針),需要添加析構函數
  2. 普通對象:消亡時自動調用析構函數
  3. 指針對象:注意new與delete的比對問題

2.5 值、指針、引用

2.5.1 value 與 reference

  1. value:預設為淺拷貝,記憶體開銷大
  2. reference:變量别名,共享記憶體
  3. 傳回局部變量時,不能聲明為reference,因為局部變量在函數結束時銷毀

2.5.2 reference 與 pointer

  1. pointer可能為null,reference必須被初始化
  2. pointer可以改變,reference不能更改

二、示例

1.類不含指針(Complex)

代碼如下(示例):

#include<iostream>

using namespace std;

class Complex{

private:
	double real, imag;
public:
	//預設構造函數
	Complex(){ } 
	//重載構造函數 + 初始化清單 
	Complex(double r, double i): real(r), imag(i){ }
	//成員函數 的 操作符重載 + 臨時對象 
	Complex operator+(const Complex& c) const{
		//傳回local變量不能使用reference 
		return Complex(real + c.real, imag + c.imag); 
	}
	//全局函數 的 操作符重載 + 友元函數 
	friend ostream& operator<<(ostream& os, Complex& c);
	friend Complex& operator+=(Complex& c1, const Complex& c2);
	/*
	Complex& operator+=(const Complex& c2)
	{
		this->real += c2.real;
		this->imag += c2.imag; 
	} 
	*/ 
};

Complex& operator+=(Complex& c1, const Complex& c2){
	c1.real += c2.real;
	c1.imag += c2.imag;
	return c1;
}
ostream& operator<<(ostream& os, Complex& c){
	os << "(" << c.real << "," << c.imag << ")";
	return os;
}

int main()
{
	Complex c1;
	Complex c2(5,5);
	const Complex c3(5,5);
	c2 += c3;
	c1 = c2 + c3;
	cout<<c1<<endl;
} 


           

2.類含指針(String)

代碼如下(示例):

#include<iostream>
#include<cstring>
/*
注: 
cstring:c++版的string.h 
string: stl範疇
string.h: c語言庫,c++相容 
*/ 


using namespace std;

class String{
private:
	char* m_data;
public:
	String(const char* cstr = 0);
	//copy ctor 
	String(const String& s);
	//copy op=
	String& operator=(const String& s);
	//析構函數
	~String(); 
	
	char* get_str() const{
		return m_data;
	}
	
	friend ostream& operator<<(ostream& os, const String& s);
};

//注:不能同時在 聲明 和 定義 中寫預設參數 
inline
String::String(const char* cstr){
	if(cstr){
		m_data = new char[strlen(cstr) + 1];
		strcpy(m_data, cstr);
	}
	else{
		m_data = new char[1];
		*m_data = '\0';
	}
	
}

inline
String::~String(){
	delete[] m_data;
}

inline
String::String(const String& s){
	//深拷貝 
	m_data = new char[ strlen(s.m_data) + 1 ];
	strcpy(m_data, s.m_data); 
}

inline
String& String::operator=(const String& s){
	//step1:檢查自我指派
	//注意指針細節:&s,this:位址;s,*this:string内容 
	if(&s == this){
		return *this;
	} 
	//step2:删除空間
	delete[] m_data;
	//step3:copy ctor
	m_data = new char[ strlen(s.m_data) + 1 ];
	strcpy(m_data, s.m_data);
	return *this; 
}

ostream& operator<<(ostream& os, const String& s)
{
	os<<s.get_str();
	return os;
}

int main()
{
	const String s2("duan");
	const String s3("shuai");
	String s1(s2);
	cout<<s1<<endl;
	s1 = s3;
	cout<<s1<<endl;
}