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

歡迎訪問 生活随笔!

生活随笔

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

c/c++

C++模板:类模板和类模板的友元【C++模板】(57)

發布時間:2025/3/20 c/c++ 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++模板:类模板和类模板的友元【C++模板】(57) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

  • 類模板
  • Stack 類
  • 類模板
    • 格式
    • 類模板的應用
    • 類模板的多文件實現
  • 類模板的友元
    • 類模板中的友元在.h
    • 類模板中的友元在.cpp
    • hpp
  • STL入門

類模板

Stack 類

我們先給出我們之前實現的棧結構:

#include <iostream> #include <stdlib.h> #include <stdio.h> #include <string.h> using namespace std; class Stack { public:Stack(int size = 1024){space = new int[size];top = 0;}~Stack() {delete[]space;}bool isEmpty() {return top == 0;}bool isFull() {return top == 1024;}void push(int data) {space[top++] = data;}int pop() {return space[--top];} private:int* space;int top; }; int main() {Stack s(100);for (int i = 0; i < 10; ++i) {if (!s.isFull())s.push(i);}while (!s.isEmpty())cout << s.pop() << endl;return 0; }

運行結果為:

上面代碼中如果我們要對于棧結構進行泛化,最主要的就是對于int * space 存儲空間的泛化。

Stack 類模板化,可以 push 和 pop 不同的數據類型。主要由幾個因素需要把控。

只需要保持棧中的空間元素類型,壓入元素類型,彈出元素類型,三者保持一致就能夠實現泛化。

類模板

格式

template<typename T> class ClassName {void func(T ); };template<typename T> void ClassName<T>::func(T) {}

類模板的應用

我們在函數模板中使用的時候先寫函數模板,然后進行函數模板的實例化形成模板函數,然后對于實例化之后的模板函數進行調用。
myswap() --> myswap() --> myswap()(a,b)
函數模板 --> 模板函數 --> 函數調用

對比到類模板就是:
類模板 --> 模板類 --> 類對象的創建
stack --> stack --> stack s(100)

我們現在對于上面的棧類進行泛化:

#include <iostream> #include <stdlib.h> #include <stdio.h> #include <string.h>using namespace std;template <typename T>class Stack { public:Stack(int size = 1024){space = new T[size];top = 0;}~Stack() {delete[]space;}bool isEmpty() {return top == 0;}bool isFull() {return top == 1024;}void push(T data) {space[top++] = data;}T pop() {return space[--top];} private:T* space;int top; }; int main() {Stack<int> s;//類模板的實例化 生成模板類 并且創建類對象for (int i = 0; i < 10; i++){if (!s.isFull())s.push(i * 11);}while(!s.isEmpty()){cout << s.pop() << endl;}return 0; }

運行結果為:

類內函數的聲明和定義分開的實現:

#include <iostream> #include <stdlib.h> #include <stdio.h> #include <string.h>using namespace std;template <typename T> //類模板 class Stack { public:Stack(int size = 1024);~Stack();bool isEmpty();bool isFull();void push(T data);T pop();private:T* space;int top; };template <typename T> Stack<T>::Stack(int size) {space = new T[size];top = 0; }template <typename T> Stack<T>::~Stack() {delete[]space; }template <typename T> bool Stack<T>::isEmpty() {return top == 0; }template <typename T> bool Stack<T>::isFull() {return top == 1024; }template <typename T> void Stack<T>::push(T data) {space[top++] = data; }template <typename T> T Stack<T>::pop() {return space[--top]; }int main() {Stack<int> s;//類模板的實例化 生成模板類 并且創建類對象for (int i = 0; i < 10; i++){if (!s.isFull())s.push(i * 10);}while (!s.isEmpty()){cout << s.pop() << endl;}return 0; }

運行結果為:

類模板的多文件實現

main.cpp

#include <iostream> #include <stdlib.h> #include <stdio.h> #include <string.h> #include "mystack.h" #include "mystack.cpp" using namespace std;int main() {Stack<int> s;//類模板的實例化 生成模板類 并且創建類對象for (int i = 0; i < 10; i++){if (!s.isFull())s.push(i * 10);}while (!s.isEmpty()){cout << s.pop() << endl;}return 0; }

mystack.cpp

#include "mystack.h"template <typename T> Stack<T>::Stack(int size) {space = new T[size];top = 0; }template <typename T> Stack<T>::~Stack() {delete[]space; }template <typename T> bool Stack<T>::isEmpty() {return top == 0; }template <typename T> bool Stack<T>::isFull() {return top == 1024; }template <typename T> void Stack<T>::push(T data) {space[top++] = data; }template <typename T> T Stack<T>::pop() {return space[--top]; }

mystack.h

#pragma once template <typename T> //類模板 class Stack { public:Stack(int size = 1024);~Stack();bool isEmpty();bool isFull();void push(T data);T pop();private:T* space;int top; };

運行結果為:

這里需要強調的是,我們在實現多文件變成的時候并不是簡單的把之前類內函數的定義和實現分開,然后在多文件中編寫,而是需要注意需要在main函數中加入#include “mystack.cpp”才能夠編譯成功和運行。

那么為什么是需要加上#include “mystack.cpp”

我們在類模板的友元中進行說明。

類模板的友元

類模板中的友元在.h

友元函數,實現在.h 文件中并不多見,但在模板中這樣使用友元,就是一種常規則用法。

main.cpp

#include <iostream> #include "mylist.h" #include "mylist.cpp"using namespace std; using namespace listspace;int main() {GenericList<int> first_list(2);first_list.add(1);first_list.add(2);cout <<"first_list"<< first_list << endl;GenericList<char> second_list(10);second_list.add('A');second_list.add('B');second_list.add('C');cout << second_list<<second_list << endl;return 0; }

mylist.cpp

#ifndef __MYLIST_ CPP__ #define __MYLIST_ CPP__ #include <iostream> #include <cstdlib> #include "mylist.h"using namespace std; namespace listspace {template<class ItemType>GenericList<ItemType>::GenericList(int max): _maxLength(max), _curIdx(0){_item = new ItemType[max];}template<class ItemType>GenericList<ItemType>::~GenericList(){delete[] _item;}template<class ItemType>int GenericList<ItemType>::length() const{return (_curIdx);}template<class ItemType>void GenericList<ItemType>::add(ItemType new_item){if (full()){cout << "Error: adding to a full list.\n";exit(1);}else{_item[_curIdx] = new_item;_curIdx = _curIdx + 1;}}template<class ItemType>bool GenericList<ItemType>::full() const{return (_curIdx == _maxLength);}template<class ItemType>void GenericList<ItemType>::erase(){_curIdx = 0;} } #endif

mylist.h

#ifndef __MYLIST_H H__ #define __MYLIST_H H__ #include <iostream> #include <ostream> using namespace std;namespace listspace { template<class ItemType>class GenericList { public:GenericList(int max);~GenericList();int length() const;void add(ItemType new_item);bool full() const;void erase();friend ostream & operator<<(ostream & out,GenericList<ItemType>& list){for (int i = 0; i < list._curIdx; i++){out << list._item[i];}return out;}private:ItemType* _item;int _maxLength;int _curIdx;}; }//listspace #endif //__MYLIST_H__

運行結果為:


使用類模板的友元時,在模板的.h文件類的聲明處定義和實現友元函數。

類模板中的友元在.cpp

mylist.cpp

#ifndef __MYLIST_ CPP__ #define __MYLIST_ CPP__ #include <iostream> #include <cstdlib> #include "mylist.h"using namespace std; namespace listspace {template<class ItemType>GenericList<ItemType>::GenericList(int max): _maxLength(max), _curIdx(0){_item = new ItemType[max];}template<class ItemType>GenericList<ItemType>::~GenericList(){delete[] _item;}template<class ItemType>int GenericList<ItemType>::length() const{return (_curIdx);}template<class ItemType>void GenericList<ItemType>::add(ItemType new_item){if (full()){cout << "Error: adding to a full list.\n";exit(1);}else{_item[_curIdx] = new_item;_curIdx = _curIdx + 1;}}template<class ItemType>bool GenericList<ItemType>::full() const{return (_curIdx == _maxLength);}template<class ItemType>void GenericList<ItemType>::erase(){_curIdx = 0;}template<class ItemType>ostream & operator<< (ostream& out, GenericList<ItemType> & list){for (int i = 0; i < list._curIdx; i++){out << list._item[i];}return out;} } #endif

mylist.h

#ifndef __MYLIST_H H__ #define __MYLIST_H H__ #include <iostream> #include <ostream> using namespace std; namespace listspace {template<class ItemType>class GenericList;template<class ItemType>ostream & operator<<(ostream& out, GenericList<ItemType>& list);template<class ItemType> class GenericList { public:GenericList(int max);~GenericList();int length() const;void add(ItemType new_item);bool full() const;void erase();//友元函數聲明friend ostream& operator<< <>(ostream& out, GenericList<ItemType>& list);private:ItemType* _item;int _maxLength;int _curIdx;}; }//listspace #endif //__MYLIST_H__

main.cpp

#include <iostream> #include "mylist.h" #include "mylist.cpp"using namespace std; using namespace listspace; int main() {GenericList<int> first_list(2);first_list.add(1);first_list.add(2);cout <<"first_list"<< first_list << endl;GenericList<char> second_list(10);second_list.add('A');second_list.add('B');second_list.add('C');cout << second_list<<second_list << endl;return 0; }

運行結果為:

在類模板的 .cpp 文件中實現友元的時候需要進行以下操作:
① 在類中聲明<> 表明是一個空體聲明。
② 在類外實現,和其他函數實現相同,需要加上類型模板。
③ 在類的聲明的前面,對類模板的友元函數作前向聲明。并且在其前面作類的前向聲明。

所以一般建議讀者在.h文件中實現類模板的友元。

但是呢,我們平時在使用到時候很少會有#include “mylist.cpp”這樣的操作,所以我們引入hpp

hpp

由于編譯器需要通過這些"模板"為實例化類型生成實際的方法代碼,因此任何使用了模板的源代碼文件中,編譯器都應該能同時訪問類模板定義和方法定義。

C++中的編譯是以文件為單位的,然后鏈接階段完成鏈接。如果模板的聲明與實現分開,這種機制顯然會導致看不到模板的全貌,而致編譯失敗。所以常將類模板定義和方法定義放到一起,該類模板文件的后綴常為.hpp,以示與普通文件的區別。在使用的時候,#include"xx.hpp"。

代碼演示:

mylist.hpp

#ifndef __MYLIST_H H__ #define __MYLIST_H H__ #include <iostream> #include <ostream> using namespace std;namespace listspace {template<class ItemType>class GenericList;template<class ItemType>ostream & operator<<(ostream& out, GenericList<ItemType>& list);template<class ItemType>class GenericList{public:GenericList(int max);~GenericList();int length() const;void add(ItemType new_item);bool full() const;void erase();friend ostream& operator<< <>(ostream& out, GenericList<ItemType>& list);private:ItemType* _item;int _maxLength;int _curIdx;}; }//listspace #endif //__MYLIST_H__#ifndef __MYLIST_ CPP__ #define __MYLIST_ CPP__ #include <iostream> #include <cstdlib> #include "mylist.h"using namespace std; namespace listspace { template<class ItemType> GenericList<ItemType>::GenericList(int max): _maxLength(max), _curIdx(0) {_item = new ItemType[max]; } template<class ItemType> GenericList<ItemType>::~GenericList() {delete[] _item; } template<class ItemType> int GenericList<ItemType>::length() const {return (_curIdx); } template<class ItemType> void GenericList<ItemType>::add(ItemType new_item) {if (full()){cout << "Error: adding to a full list.\n";exit(1);}else{_item[_curIdx] = new_item;_curIdx = _curIdx + 1;} } template<class ItemType> bool GenericList<ItemType>::full() const {return (_curIdx == _maxLength); } template<class ItemType> void GenericList<ItemType>::erase() {_curIdx = 0; }template<class ItemType> ostream& operator<< (ostream& out, GenericList<ItemType>& list) {for (int i = 0; i < list._curIdx; i++){out << list._item[i];}return out; } } #endif

main.cpp

#include <iostream> #include "mylist.hpp"using namespace std; using namespace listspace; int main() {GenericList<int> first_list(2);first_list.add(1);first_list.add(2);cout <<"first_list"<< first_list << endl;GenericList<char> second_list(10);second_list.add('A');second_list.add('B');second_list.add('C');cout << second_list<<second_list << endl;return 0; }

運行結果為:

模板通過會將聲明和實現放在一個文件中,及就是.hpp中。這樣做的原因就是,C語言和C++的編譯模式是按照文件進行編譯的。

模板在進行實例化的時候,是需要看到整個模板的全部內容,及就是模板的定義和實現的全部代碼。所以如果只有.h的話,實例化的時候僅僅只是看到模板的聲明,并不能看到模板的實現,所以需要使用.hpp來實現。把模板的聲明和實現放在一起。

也就是說在任何需要實例化的地方,都需要看到模板的全部的聲明和定義。

STL入門

代碼演示:

#include <iostream> #include <vector> #include <stdlib.h> #include <time.h> #include <algorithm> using namespace std;int main() {srand(time(nullptr));vector<int> vi; //類模板的實例化,生成模板類,并且創建類對象 vifor (int i = 0; i < 10; i++){vi.push_back(rand() % 100);}sort(vi.begin(), vi.end(), [](int x, int y) {return x < y; });for (auto i : vi)cout << i << endl;return 0; }

運行結果:

引入內存管理機制,一開始不需要指定大小。

總結

以上是生活随笔為你收集整理的C++模板:类模板和类模板的友元【C++模板】(57)的全部內容,希望文章能夠幫你解決所遇到的問題。

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