日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

      歡迎訪問 生活随笔!

      生活随笔

      當前位置: 首頁 > 编程语言 > c/c++ >内容正文

      c/c++

      C++学习笔记:(一)面向对象 类与对象

      發布時間:2024/2/28 c/c++ 22 豆豆
      生活随笔 收集整理的這篇文章主要介紹了 C++学习笔记:(一)面向对象 类与对象 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

      目錄

      1.面向對象的概念

      2.類與對象

      2.1?類的定義格式

      2.2 對象的定義與使用

      2.3 構造函數和析構函數

      2.4 內存的動態分配

      2.5 對象數組和對象指針

      2.6 函數參數的傳遞機制

      2.7 友元


      1.面向對象的概念

      早期的計算機編程是基于面向過程的方法,例如實現算術運算1+1+2 = 4,通過設計一個算法就可以解決當時的問題。隨著計算機技術的不斷提高,計算機被用于解決越來越復雜的問題。一切事物皆對象,通過面向對象的方式,將現實世界的事物抽象成對象,現實世界中的關系抽象成類,幫助人們實現對現實世界的抽象與數字建模。通過面向對象的方法,更利于用人理解的方式對復雜系統進行分析、設計與編程。同時,面向對象能有效提高編程的效率,通過封裝技術,消息機制可以像搭積木的一樣快速開發出一個全新的系統。面向對象是指一種程序設計范型,同時也是一種程序開發的方法。它將對象作為程序的基本單元,將程序和數據封裝其中,以提高軟件的重用性、靈活性和擴展性。

      面向對象三大基本特征:封裝、繼承和多態。具體概念可以慢慢理解。其實這也是C和C++不一樣的地方。如果我們要做一個學生管理系統,分別用C和C++來編程,就可以看到面向對象和面向過程的區別。面向對象和面向過程都是編程思想,C++可以用面向過程的思想編程,C也可以用面向對象的思想編程(但是很麻煩)。

      //C:結構體 typedef struct Student {long no;char name[10];float score; }; void findnumber(long no); void findname(char name[]); void Print(); //C++:類 class Student { private:long no;char name[10];float score; public:Student();void findnumber(long no);void findname(char name[]);void Print(); };

      對比兩者的定義來學習第一個概念封裝:封裝就是把客觀事物封裝成抽象的類。是對象和類概念的主要特性。 簡單的說,一個類就是一個封裝了數據以及對這些數據進行操作的代碼的邏輯實體。在一個對象內部,某些函數成員或某些數據成員可以是私有的,不能被外界訪問。C++中,封裝是通過類來實現的。

      再從兩者的定義來看,C中函數和結構體是分開的,可以說這些函數是對外公開的,只要滿足參數的要求就可以調用這個函數(這里不需要關注調用的結果,只是為了說明一個權限問題)。而C++中函數成員和數據成員會根據具體要求設置不同的權限,這樣就對數據起到了保護作用,而且這些函數只能被本類對象調用。還有命名問題,若在C中有多個結構體都需要打印功能,就要防止命名相同的情況出現。而在C++中定義一個成員函數:void Student::Print()表明這個Print()是類Student的函數成員,其他的類也可以有Print()函數。例如:Student a; ?Asd b;在使用Print()函數時分別是a.Print();和b.Print()。

      這里簡單了解封裝的概念即可,學習完類和對象有助于學習繼承和多態。現在簡單說一下類和對象的關系。它們是一般和特殊、共性和特性的關系。如果知道“白馬非馬”,對理解類和對象是很有幫助的。類是一種數據類型,也是實現抽象類型的工具。類是對一組具有共同屬性特征和行為特征的對象的抽象,并將相關數據和對數據的操作組合在一起。在Student類中,數據就是學生的學號,姓名和成績,操作是按學號查找、按名查找以及打印。當定義了Student a1;那么a1就從抽象變成了具體,我們可以用它來表示一個學生,并將學號、姓名和成績輸入其中。

      ?

      2.類與對象

      2.1?類的定義格式

      class 類名 { private:數據成員或成員函數 protected:數據成員或成員函數 public:數據成員或成員函數 };

      類的成員包括兩類成員,一類是代表對象屬性的數據成員,另一類是實現對象行為的成員函數。成員函數的定義可以與聲明同時在類里面完成,也可以在類外面完成。如果在類外面完成,就要使用作用域”::”符號告訴編譯系統該函數所屬的類。

      ?

      2.1.1訪問權限:

      訪問權符也稱為訪問權限符或訪問控制符,它規定類中說明的成員的訪問屬性,是C++語言實現封裝的基本手段。C++提供了三種不同的訪問權限符:private、protected和public。

      (1)public(公有類型):表示這個成員可以被該類對象處在同一作用域內的任何函數使用。一般將成員函數聲明為公有的訪問控制。

      (2)private(私有類型):表示這個成員能被它所在的類中的成員函數&該類的友元函數使用。

      (3)protected(保護類型):表示這個成員只能被它所在類&從該類派生的子類的成員函數&友元函數使用。

      具體使用的時候,應該根據成員的使用特點決定對其封裝的程度。通常的做法是,將數據成員聲明為私有或保護的,將對象向外界提供的接口或服務聲明為公有的成員函數。如果某些數據成員在子類中也需要經常使用,則應該把這些數據聲明為保護類型。例:

      class Book { private:char title[20],author[10],publish[30];float price; public:void Input();void Print(); };

      (1)類聲明中的三個關鍵字可以按任意順序出現。為了程序更加清晰,應將私有成員、保護成員、和公有成員歸類存放。默認的訪問權限是私有的(private)。

      (2)對于一個具體的類,類聲明中的private、public和protected三個部分不一定都要出現,但至少應該有其中一個部分。

      (3)數據成員可以是任意數據類型,但不能是自動(auto)、寄存器(register)或外部(extern)類型。

      (4)由于類是一種數據類型,系統并不會為其分配內存空間,所以不能在類聲明中給數據成員賦初值。

      ?

      C++使用cin/cout控制輸入/輸出。

      (1)cin,表示標準輸入的istream類對象。cin從終端讀入數據。

      (2)cout,表示標準輸出的ostream類對象。cout向終端寫數據。

      為了在程序中使用cin/cout,必須要加iostream庫的相關頭文件#include <iostream>

      iostream類同時從istream類和ostream類派生而來,允許雙向輸入/輸出。輸入有重載的操作符>>完成,輸出由重載的操作符<<來完成。輸入輸出格式:

      cin >> 變量名; cout << 變量名或常量;命名空間的知識會在后面出現,如若不加就要寫成: std::cin >> a; std::cout << "hello ! C++\n";? std::cout << "hello ! C++" << std::endl; #include <iostream> using namespace std; int main() {int a;cin >> a;cout << "A:" << a <<endl;cout << "hello! C++\n";cout << "hello! C++" <<endl;return 0; }

      ?

      2.1.2成員函數的定義

      一般代碼量較少的成員函數可以在類中定義,而代碼量較大的成員函數,通常在類中進行函數原型的說明,在類外對函數進行定義,其形式是:

      返回類型 ?類名::函數名(參數表) {//函數體 }

      例:

      void Book::Input() {cin >> title >> author >> publish >> price; } void Book::Print() {cout << title <<"?"<< author <<"?"<< publish <<" "<< price <<endl; ? }

      (1)如果在類外定義成員函數,則應該在所定義的成員函數名前加上類名,在類名和函數名之間應加上作用域運算符“::”,它說明成員函數從屬哪個類。

      (2)定義成員函數時,對函數所帶的參數,不但要說明它的類型,還要指出其參數名。

      (3)在定義成員函數時,其返回類型一定要與函數原型聲明的返回類型匹配。

      ?

      2.2 對象的定義與使用

      在C++中,聲明了類,只是定義了一個新的數據類型,只有定義了類的對象,才能真正創建了這種數據類型的物理實體。對象是封裝了數據結構及可以施加在這些數據結構上的操作的封裝體。對象就是類的實際變量,一個具體的對象是類的一個實例。類和對象的關系,就類似于整型int和整型變量i的關系。類類型和整型int均是一般的概念,而對象和整型變量則代表具體的東西。與定義一般變量一樣,可以定義類的變量。C++把類的變量稱為類的對象,一個具體的對象也稱為類的實例。

      兩種定義對象的方法:

      (1)在聲明類的同時,直接定義對象。

      class Book { private:char title[20],author[10],publish[30];float price; public:void Input();void Print(); }b1,b2; //表示定義b1,b2是Book類的對象。

      (2)先聲明類。然后在使用的時候再定義對象,其格式:

      類名 ?對象名列表;

      (1)必須定義了類以后,才能定義類的對象。

      (2)聲明了一個類就聲明了一種類型,它并不能接收和存儲具體的值,只能作為生成具體對象的一種“模板”,只有定義了對象后,系統才為對象分配存儲空間。

      (3)在聲明類的同時定義的對象是一種全局對象,在它的生存期內任何函數都可以使用它,一直到整個程序運行結束。

      對象的使用:

      使用對象,就是向對象發送消息,請求執行它的某個方法,從而向外界提供所要求的服務。形式如下:

      對象名.成員函數名(實參表);

      例如:Book b1(實參);

      (1)在使用對象賦值語句進行賦值時,兩個對象的類型必須相同。賦值兼容規則除外。

      (2)兩個對象間的賦值,僅僅使這些對象中的數據相同,而兩個對象仍然是彼此獨立的,各自有自己的空間。

      (3)如果類中存在指針,則不能簡單的將一個對象的值賦給另一個對象,否則可能會產生錯誤。

      ?

      2.3 構造函數和析構函數

      構造函數的功能是在創建對象時,給數據成員賦值,即對象的初始化。析構函數的功能是釋放一個對象,在對象刪除之前,用它來做一些內存釋放等清理工作,它的功能與構造函數的功能正好相反。

      定義構造函數原型的格式:

      類名(形參列表);

      在類外定義構造函數的格式為:

      類名::類名(形參列表) {//函數語句; }

      構造函數的特點:

      (1)構造函數的名字必須與類名相同。

      (2)構造函數可以有任意類型的參數,但是沒有返回值類型,也不能指定為void類型。

      (3)定義對象的時候,系統會自動調用構造函數。

      (4)如果沒有定義構造函數,系統會自動生成一個默認的構造函數,只負責對象的創建,不做初始化工作。

      (5)構造函數可以重載。

      ?

      使用構造函數時容易犯的錯,即不需要初始化時調用相應的構造函數,而不能與別的構造函數弄混。

      #include <iostream> using namespace std;class Foo {public:Foo() { cout << "foo:1" <<endl; }Foo(int) { cout << "foo:2" <<endl; }void fun(){} };struct Asd {Asd() { cout << "asd:1" <<endl; }Asd(int) { cout << "asd:2" <<endl; }void fun(){} };int main(void) {Foo a(10); //語句1a.fun(); //語句2cout <<endl;Foo b(); //語句3b.fun(); //語句4return 0; }

      改成Foo b;便可解決問題,這不是一個難題,但是往往容易忽略。代碼中有個 struct ,寫這個代碼主要是為了說明,在 struct 中,成員默認屬性是 public,而在 class 中,成員默認屬性是 private。

      ?

      定義析構函數的一般格式:

      ~類名();

      析構函數的特點:

      (1)析構函數沒有參數,也沒有返回值,而且不能重載。

      (2)一個類中有且僅有一個析構函數,且應該為public。

      (3)析構函數的功能是釋放對象所占用的內存空間。

      (4)析構函數與構造函數兩者的調用次序相反,即最先構造的對象最后被析構,最后構造的對象最先被析構。

      (5)如果一個對象被定義在一個函數體內,則當這個函數體結束時,該對象的析構函數會被自動調用。

      ?

      2.4 內存的動態分配

      用戶存儲區空間分為三個部分,程序區(代碼區)、靜態存儲區和動態存儲區(棧區和堆區)。代碼區存放程序代碼,程序運行前就分配存儲空間。數據區存放常量、靜態變量、全局變量等。棧區存放局部變量、函數參數、函數返回值和臨時變量等。堆區是程序空間中存放在的一些空閑存儲單元,這些空閑存儲單元組成堆。在堆中創建的數據對象為堆對象。當創建對象時,堆中的一些存儲單元從未分配狀態變為已分配狀態;當刪除所創建的堆對象時,這些存儲單元從已分配狀態又變成未分配狀態。在C++中使用運算符new和delete來實現在堆內存區中進行數據的動態分配和釋放。

      ?

      2.4.1 運算符new

      在C++程序中,運算符new的功能是實現內存的動態分配。在程序運行過程中申請和釋放的存儲單元稱為堆對象。

      new運算符的使用格式包括三種形式:

      指針變量 = ?new T; 指針變量 = ?new T(初始值列表); 指針變量 = ?new T[元素個數];

      T是數據類型名,表示在堆中建立一個T類型的數據。

      int *p; float *p1; p = new int(100); ??//讓p指向一個類型為整型的堆地址,該地址中存放數值100 p1 = new float; ????//讓p1指向一個類型為實型的堆地址

      用new創建堆對象的格式:

      類名 *指針名 = new 類名([構造函數參數]);

      Complex *c1 = new Complex(1.1, 2.2);

      (3)new返回一個指定的合法數據類型的內存空間的首地址,若分配不成功,則返回一個空指針。

      (4)new可以為數組動態分配內存空間,這時應該在類型名后面指明數組大小。其中,元素個數是一個整型數值,可以是常數也可以是變量。

      int n ,*p; cin >> n; p = new int[n];

      (5)new不能對動態分配的數組存儲區進行初始化。

      (6)用new分配的空間,使用結束后只能用delete顯式的釋放,否則這部分空間將不能回收,從而造成內存泄漏。

      ?

      2.4.2 運算符delete

      運算符delete用來釋放動態變量或動態數組所占用的內存空間。delete運算符的應用格式:

      delete 指針變量名; ??//釋放指針p所指向的動態內存空間

      delete [] 指針變量名; ?//釋放為數組動態分配的內存

      (1)new和delete需要配套使用,如果搭配錯了,程序運行時將會發生不可預知的錯誤。

      (2)在用delete釋放指針所指向的空間時,必須保證這個指針所指向的空間時用new申請的,并且只能釋放一次,否則將產生指針懸掛問題。

      (3)如果在程序中用new申請空間,應該在結束程序前釋放所有申請的空間。這樣才能保證堆內存的有效利用。

      (4)當delete用于釋放由new創建的數組的連續內存空間時,無論是一維數組還是多維數組,指針變量名前必須使用[],且[]內沒有數字。

      1.cpp

      #include <iostream> using namespace std; class Point {private:int x,y;public:Point(int a, int b);~Point(); };Point::Point(int a, int b) {cout << "constructor..." <<endl;x = a;y = b; }Point::~Point() {cout << "destructor..." <<endl; }int main() {Point *p = new Point(1, 3);delete p;return 0; }

      ?

      2.5 對象數組和對象指針

      數組元素可以是基本數據類型的數據,也可以是用戶自定義數據類型的數據。對象數組是指每一個數組元素都是對象的數組。對象數組的元素是對象,它不僅具有數據成員,而且還有函數成員。

      聲明對象數組的形式:

      類名 數組名[下標表達式];

      與基本類型的數組一樣,在使用對象數組時也只能引用單個數組元素。通過對象,可以訪問它的公有成員。對象數組的引用形式:

      數組名[下標].成員函數

      2.cpp

      #include <iostream> using namespace std;class Circle {private:double radius;public:Circle(double r);double Area();~Circle(); };Circle::Circle(double r) {cout << "construct..." <<endl;radius = r; }double Circle::Area() {return 3.14*radius*radius; }Circle::~Circle() {cout << "destruct..." <<endl; }int main() {Circle c[3] = {1,3,5};int i;for(i = 0; i < 3; i++){cout <<c[i].Area() <<endl;}return 0; }

      3.cpp

      #include <iostream> using namespace std;class Point {private:int x,y;public:Point(int a, int b);void Print(); };Point::Point(int a, int b) {x = a;y = b; }void Point::Print() {cout << "(" << x << "," << y << ")" <<endl; }int main() {Point a[3] = {Point(1,2), Point(3,4), Point(5,6)};int i;for(i = 0; i < 3; i++){a[i].Print();}return 0; }

      ?

      2.5.1 對象指針

      訪問一個對象可以通過對象名訪問,也可以通過對象地址訪問。對象指針就是用于存放對象地址的變量。對象指針遵循一般變量指針的各種規則,聲明對象指針的一般語法形式:

      類名 *對象指針名;

      使用對象指針也可以訪問對象的成員:

      對象指針名->成員名

      與一般變量指針一樣,對象指針在使用前必須先進行初始化。可以讓它指向一個已經聲明過的對象,也可以用new運算符動態建立堆對象。

      circle *c1,c(3); c1 = &c; c1->Area(); ?????//正確,c1指向的是一個已經聲明過的對象 cirlce *c2 = new Circle(3); c2->Area(); ?????//正確,c2使用new運算符動態建立的堆對象c2 circle *c3; c3->Area(); ?????//錯誤,不能使用沒有初始化的對象指針

      2.cpp中main可改為:

      int main() {Circle c[3] = {1,3,5};Circle *p = c;for(; p < 3; p++){cout << p->Area() <<endl;}return 0; }

      2.5.2 自引用指針this

      this指針主要用在運算符重載和自引用等場合。

      4.cpp

      #include <iostream> using namespace std;class Square {private:double a;public:Square(double a);double Area();void copy(Square &s); };Square::Square(double a) {this->a = a; }double Square::Area() {return a*a; }void Square::copy(Square &s) {if(this == &s)return;*this = s; }int main() {Square s1(3),s2(5);cout << "before copy" <<endl;cout << "s1 area is " << s1.Area() <<endl;cout << "after copy" <<endl;s1.copy(s2);cout << "s1 area is " << s1.Area() <<endl; }

      定義對象s1時通過構造函數將其數據成員初始化為3,因此調用Area函數輸出9;當程序執行s1.copy(s2)時,對象s1調用成員函數copy,因此this指針指向s1。在copy函數中首先判斷是不是對象在給自己賦值,如果是,就返回;否則,將形參s的值賦給this所指的對象s1。在Square::Sqare(double a)中,因為私有成員是a,而參數名也是a,此時要使用this指針告訴編譯器是把參數a的值給私有成員a。

      使用this指針時應該注意:

      (1)this指針是一個const指針,不能再程序中修改或給它賦值。

      (2)this指針是一個局部數據,它的作用域僅在一個對象的內部。

      (3)靜態成員函數不屬于任何一個對象。在靜態成員函數中沒有this指針。

      ?

      2.6 函數參數的傳遞機制

      C語言中,函數的參數傳遞有兩種方式:按變量值傳遞和按變量的地址傳遞,C++語言不僅可以實現上述兩種參數傳遞方式,還可以進行引用傳遞。而且在C++語言中,不僅簡單變量可以作為參數進行傳遞,對象也可以作為參數傳遞給函數,其方法與傳遞其他類型的數據一樣。

      2.6.1 使用對象作為函數參數

      5.cpp

      #include <iostream> #include <iomanip> using namespace std; class Point {private:int x,y;public:Point(int a, int b);void Add(Point p);void Print(); };Point::Point(int a, int b) {x = a;y = b; }void Point::Print() {cout << "x:" << x << setw(5) << "y:" << y <<endl; }void Point::Add(Point p) {p.x = p.x + 1;p.y = p.y + 1; }int main() {Point ob(1,2);cout << "before add:";ob.Print();ob.Add(ob);cout << "after add:";ob.Print();return 0; }

      在執行Add函數時,由于作為參數的對象時按值傳遞的,也就是實參ob將自己的值對應的賦給形參p,在Add函數中對形參p的數據成員x和y值得修改結果并沒有傳回主程序中。

      ?

      2.6.2 使用對象指針作為函數參數

      6.cpp

      #include <iostream> #include <iomanip> using namespace std; class Point {private:int x,y;public:Point(int a, int b);void Add(Point *p);void Print(); };Point::Point(int a, int b) {x = a;y = b; }void Point::Print() {cout << "x:" << x << setw(5) << "y:" << y <<endl; }void Point::Add(Point *p) {p->x = p->x + 1;p->y = p->y + 1; }int main() {Point ob(1,2);cout << "before add:";ob.Print();ob.Add(&ob);cout << "after add:";ob.Print();return 0; }

      對象指針作為參數傳遞給函數,是傳地址,即形參和實參共享的是同一內存單元。因此,作為形參的對象,其數據的改變將影響實參對象,從而實現函數之間的信息傳遞。此外,使用對象指針作為參數僅將對象的地址傳遞給形參,而不進行副本的復制,可以提高運行效率,減少時空開銷。

      ?

      2.6.3 使用對象引用作為函數參數

      引用相當于變量的別名,聲明引用的格式:

      數據類型 &引用名 = 已定義的變量名; int &j = i; ?//表示j是i的引用,j相當于i的別名。變量i和j對應同一內存單元,當i變化,j也隨著變化,反之亦然。 Point &p = ob; ?//ob是一個已定義的Point類的對象,對象p是對象ob的引用。

      7.cpp

      #include <iostream> #include <iomanip> using namespace std; class Point {private:int x,y;public:Point(int a, int b);void Add(Point &p);void Print(); };Point::Point(int a, int b) {x = a;y = b; }void Point::Print() {cout << "x:" << x << setw(5) << "y:" << y <<endl; }void Point::Add(Point &p) {p.x = p.x + 1;p.y = p.y + 1; }int main() {Point ob(1,2);cout << "before add:";ob.Print();ob.Add(ob);cout << "after add:";ob.Print();return 0; }

      ?

      2.6.4 三種傳遞方式比較

      (1)使用對象作為函數參數:當進行函數調用時,需要給形參分配存儲單元,形參和實參的結合是值傳遞,實參將自己的值傳遞給形參,形參實際上是實參的副本,這是一種單向傳遞,形參的變化不會影響到實參。

      (2)使用指針作為函數參數:這種形式,實參將自己的地址傳遞給形參,這是一種雙向傳遞,形參的變化會直接影響到實參。

      (3)使用引用作為函數參數:當進行函數調用時,在內存中并沒有產生實參的副本,它是直接對實參操作;這種方式是雙向傳遞,形參的變化會直接影響到實參。與指針做函數參數比較,這種方式更容易使用、更清晰。而且當參數傳遞的數據較大時,用引用比用一般傳遞參數的效率和所占空間都好。

      ?

      2.7 友元

      類的主要特點之一是數據隱藏,也就是類的私有成員或保護成員只能通過它的成員函數來訪問。C++中提供了友元機制來解決在類外對某個對象的私有成員或保護成員進行操作。友元可以是不屬于任何類的一般函數,也可以是另一個類的成員函數,還可以是整個的一個類(這是,這個類的所有成員函數都可以成為友元函數)。

      ?

      2.7.1 友元函數

      友元函數不是當前類中的成員函數,它可以是一個不屬于任何一個類的一般函數,也可以是另一個類的成員函數。當函數被聲明為一個類的友元函數后,它就可以通過對象訪問類的私有成員和保護成員。

      非成員函數作為友元函數,其作為類的友元函數后,就可以通過對象訪問封裝在類內部的數據。聲明友元函數:

      friend 函數返回值 函數名(形參表);

      8.cpp

      #include <iostream> using namespace std;class Complex {private:double real;double imag;public:Complex(double r, double i);void Print();friend Complex add(Complex c1, Complex c2); };Complex::Complex(double r, double i) {real = r;imag = i; }void Complex::Print() {cout <<real;if(imag > 0)cout << "+";if(imag != 0)cout << imag << "i" <<endl; }Complex add(Complex c1, Complex c2) {c1.real = c1.real + c2.real;c1.imag = c1.imag + c2.imag;return c1; }int main() {Complex com1(1.1, 2.2),com2(3.3, 4.4);com1 = add(com1, com2);com1.Print();return 0; }

      (1)友元函數定義的時候,不用在函數面前家“類名::”,因為它不是該類的成員函數;友元函數沒有this指針;調用友元函數時必須在它的實參表中給出要訪問的對象。

      (2)友元函數可以在類的私有部分進行聲明,也可以在類的公有部分進行聲明。

      (3)當一個函數需要訪問多個類時,應該把這個函數同時定義為這些類的友元函數。

      9.cpp

      #include <iostream> using namespace std;class Time; class Date {private:int year, month, day;public:Date(int y, int m, int d);friend void Calcutetime(Date d, Time t); };class Time {private:int hour, minute, second;public:Time(int h, int m, int s);friend void Calcutetime(Date d, Time t); };Date::Date(int y, int m, int d):year(y), month(m), day(d){} Time::Time(int h, int m, int s):hour(h), minute(m), second(s){} void Calcutetime(Date d, Time t) {int mon[12] = {31,28,31,30,31,30,31,31,30,31,30,31};int i, days = 0, totaltime;for(i = 1; i < d.month; i++)days = days+mon[i-1];if ((d.year%4==0 && d.year %100 != 0 || d.year % 400 == 0) && d.month >= 3)days = days+1;totaltime = ((days*24+t.hour)*60+t.minute)*60 + t.second;cout <<d.year << '-' << d.month << '-' << d.day << " ";cout << t.hour << ':' << t.minute << ':' << t.second <<endl;cout << "total time: " << totaltime << " seconds" <<endl; }int main() {Date d(2004,10,18);Time t(14,20,25);Calcutetime(d,t);return 0; }

      如果友元函數帶了兩個不同類的對象,其中一個對象所對應的類要在后面聲明。為了避免編譯時出錯,編程時必須通過向前引用告訴C++,該類將在后面定義,如果類A用到的參數類型是后面即將定義的類B,則需要在聲明類A的前面進行一個空聲明,即class B;,表示向前引用,類B的定義在后面。

      友元函數提高了程序的運行效率,實現了類之間的數據共享,方便了編程。但是聲明友元函數相當于在實現封裝的黑盒子上開了一個黑洞,如果一個類聲明了許多友元,則相當于在黑盒子上開了許多洞,在一定程度上破壞了數據的隱蔽性和類的封裝性,降低了程序的可維護性。

      類的成員函數作為友元函數

      一個類的成員函數可以作為另一類的友元,這種成員函數不僅可以訪問自己所在類中的成員,還可以通過對象名訪問friend聲明語句所在類的私有成員和保護成員,從而使兩個類相互合作。

      10.cpp

      #include <iostream> using namespace std;class Time; class Date {private:int year, month, day;public:Date(int y, int m, int d);void Calcutetime(Time t); };class Time {private:int hour, minute, second;public:Time(int h, int m, int s);friend void Date::Calcutetime(Time t); };Date::Date(int y, int m, int d):year(y), month(m), day(d){} Time::Time(int h, int m, int s):hour(h), minute(m), second(s){} void Date::Calcutetime(Time t) {int mon[12] = {31,28,31,30,31,30,31,31,30,31,30,31};int i, days = 0, totaltime;for(i = 1; i < month; i++)days = days+mon[i-1];if ((year%4==0 && year %100 != 0 || year % 400 == 0) && month >= 3)days = days+1;totaltime = ((days*24+t.hour)*60+t.minute)*60 + t.second;cout <<year << '-' << month << '-' << day << " ";cout << t.hour << ':' << t.minute << ':' << t.second <<endl;cout << "total time: " << totaltime << " seconds" <<endl; }int main() {Date d(2004,10,18);Time t(14,20,25);d.Calcutetime(t);return 0; }

      ?

      2.7.2 友元類

      友元函數可以使函數能夠訪問某個類中的私有或保護成員。如果類A的所有成員函數都想訪問類B的私有或保護成員,一種方法是將類A的所有成員函數都聲明為類B的友元函數,但是這樣做顯得比較麻煩,且程序也顯得冗余。為此,C++提供了友元類。也就是一個類也可以作為另一個類的友元類。若類A聲明為類B的友元類,則類A中的每個成員函數都具有訪問類B的保護或私有數據成員的特權。

      ?11.cpp

      #include <iostream> using namespace std;class Complex {private:double real;double imag;public:Complex(double r, double i);friend class Vector; };class Vector {private:double x,y;public:void Change(Complex c);void Print(Complex c); };void Vector::Change(Complex c) {x = c.real;y = c.imag; }void Vector::Print(Complex c) {cout << "fushu:";cout << c.real;if(c.imag > 0)cout << "+";cout <<c.imag << "i" <<endl;cout << "Vector:";cout << "(" << x << "," << y << ")" <<endl; }Complex::Complex(double r, double i) {real = r;imag = i; }int main() {Complex c(1.1, 2.2);Vector v;v.Change(c);v.Print(c); return 0; }

      聲明友元類就像把自家的鑰匙給了另一個類,意思是你是我的朋友,我很信任你,你可以來我家,并且家里的東西你可以隨便用。

      注意:(1)友元關系是單向的。如果類A時類B的友元,則類A中的所有成員函數都可以直接訪問類B的保護和私有數據成員,反之則不能。

      (2)友元關系不能傳遞。如果類A時類B的友元,類B時類C的友元,不能推出類A就是類C的友元。友元在聲明時既可以放在類的私有部分,也可以放在類的公有部分。

      ??

      總結

      以上是生活随笔為你收集整理的C++学习笔记:(一)面向对象 类与对象的全部內容,希望文章能夠幫你解決所遇到的問題。

      如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。