C++11學習 新特性之 “=default” 、“=delete”

文章目錄

  • 1、 =default 和=delete 概述
  • 2、 類與默認函數
  • 3、 使用“=delete”來限制函數生成
  • 4、 “=default”使用范圍

1、 =default 和=delete 概述

  • =default、=delete 是C++11的新特性,分別為:顯式缺省(告知編譯器生成函數默認的缺省版本)和顯式刪除(告知編譯器不生成函數默認的缺省版本)。C++11中引進這兩種新特性的目的是為了增強對“類默認函數的控制”,從而讓程序員更加精準地去控制默認版本的函數。 其具體的功能和使用方法下面將一一道來。

2、 類與默認函數

  • 在講解關鍵字 default和delete 之前,先對類和類的默認函數作下描述與說明,從而加深對這兩個關鍵字的理解與認知。既要知其然,也要知其所以然。C++中,當設計與編寫一個類時,若不顯著寫明,則類會默認提供如下幾個函數:
    ?????(1)構造函數
    ?????(2)析構函數
    ?????(3)拷貝構造函數
    ?????(4)拷貝賦值函數(operator=)
    ?????(5)移動構造函數

    ?????以及全局的默認操作符函數:
    ?????(1)operator,
    ?????(2)operator &
    ?????(3)operator &&
    ?????(4)operator *
    ?????(5)operator->
    ?????(6)operator->*
    ?????(7)operator new
    ?????(8)operator delete

    ?????注:若我們在類中實現了這些版本之后,編譯器便不會生成其對應的默認函數版本,這時需要我們顯式的寫上其對應的默認函數版本。

#include <iostream>
using namespace std;class Student{public:Student(const int a,const int b):m_a(a),m_b(b){}int getA()const {return m_a;}int getB()const {return m_b;}private:int m_a;int m_b;
};int main(int argc,char **argv){Student stu(1,2);cout << stu.getA() << endl;//1cout << stu.getB() << endl;//2Student stu1; //編譯失敗,no matching function for call to ‘Student::Student()’return 0;
}
  • 編譯報錯,提示:Student.cpp: In function ‘int main(int, char**)’:Student.cpp:34:13: error: no matching function for call to ‘Student::Student()’ Student stu1;
  • 例1定義了一個對象stu1,該對象將會使用Student類的無參構造函數,而該默認構造函數在Student類中,我們沒有顯式的說明。因此,c++編譯器在我們提供了該函數實現之后是不會生成與之對應的默認函數版本的。在Student中我們重載了帶2個參數的構造函數,但是無參的構造函數,沒有提供,因此會報錯。

解決辦法,在該類別中顯示的提供五參數的構造函數

#include <iostream>
using namespace std;class Student{public:Student(){} //顯示說明Student的無參構造函數Student(const int a,const int b)
//        :m_a(a)
//        ,m_b(b){{{m_a = a;m_b = b;}int getA()const {return m_a;}int getB()const {return m_b;}private:int m_a;int m_b;
};int main(int argc,char **argv){Student stu(1,2);cout << stu.getA() << endl;//1cout << stu.getB() << endl;//2Student stu1; //編譯失敗,no matching function for call to ‘Student::Student()’return 0;
}

學習心得

  • :m_a(a),m_b(b)是一個賦值的運算
Student(const int a,const int b):m_a(a),m_b(b){{{}

等效于

Student(const int a,const int b){m_a = a;m_b = b;}
  • 問題:以 Student(){} 這樣的方式來聲明無參數構造函數,會帶來一個問題,就是使得 其不再是 POD 類型,因此可能讓編譯器失去對這樣的數據類型的優化功能。這是不希望看到的。因此最好使用 = default來修飾默認構造函數。
#include<iostream>
using namespace std;
class Student
{public:Student() = default;Student(const int a,const int b):m_a(a),m_b(b){}int getA()const{return m_a;}int getB()const{return m_b;}private:int m_a;int m_b;
};int main(int argc,char **argv)
{Student stu(1,2);cout<<stu.getA()<<endl; //1cout<<stu.getB()<<endl; //2Student stu1;//使用is_pod模板類可以查看某類型是否屬于POD類型,若為POD類型,則返回1,反之,返回0std::cout<<is_pod<Student>::value<<std::endl;  //1return 0;
}

3、 使用“=delete”來限制函數生成

  • C++開發中,我們經常需要控制某些函數的生成。在C++11之前,經常的普遍做法是將其聲明為類的 private 成員函數,這樣若在類外這些這些函數的操作時候,編譯器便會報錯,從而達到效果。如例2:
#include<iostream>
using namespace std;
class Student
{public:Student() = default;Student(const int a,const int b):m_a(a),m_b(b){}int getA()const{return m_a;}int getB()const{return m_b;}private:Student(const Student& );Student& operator =(const Student& );private:int m_a;int m_b;
};int main(int argc,char **argv)
{Student stu(1,2);cout<<stu.getA()<<endl; //1cout<<stu.getB()<<endl; //2//Student stu1(stu);//報錯:Student.cpp:26:5: error: ‘Student::Student(const Student&)’ is private//Student stu1(3,4);//stu1 = stu;//報錯:Student.cpp:27:14: error: ‘Student& Student::operator=(const Student&)’ is privatestd::cout<<is_pod<Student>::value<<std::endl;  //return 0;
}
  • 例2代碼編譯報錯,因為在類中,我們將Student的拷貝構造函數和拷貝賦值函數都聲明為了 private 屬性,因此,當在類外使用拷貝構造和拷貝賦值操作值,編譯器會報錯。雖然能夠達到效果,但是不夠直觀和簡潔。對于追求高效以及簡潔來說

這樣做有2個問題:
?????(1)不是最簡化;
?????(2)對于友元支持不友好

更為簡潔直觀的方法是使用: =delete

#include<iostream>
using namespace std;
class Student
{public:Student() = default;Student(const int a,const int b):m_a(a),m_b(b){}int getA()const{return m_a;}int getB()const{return m_b;}Student(const Student& ) = delete;Student& operator =(const Student& ) = delete;private:int m_a;int m_b;
};int main(int argc,char **argv)
{Student stu(1,2);cout<<stu.getA()<<endl; //1cout<<stu.getB()<<endl; //2//Student stu1(stu);//報錯:Student.cpp:39:21: error: use of deleted function ‘Student::Student(const Student&)’//Student(const Student& );//Student stu1(3,4);//stu1 = stu;//報錯:SStudent.cpp:44:10: error: use of deleted function ‘Student& Student::operator=(const Student&)’std::cout<<is_pod<Student>::value<<std::endl;  //return 0;
}

4、 “=default”使用范圍

  • "=default"不僅僅局限于類的定義內,也可以用于類的定義外來修飾成員函數,如例3:
#include<iostream>
using namespace std;
class Student
{public:Student() = default;Student(const int a,const int b):m_a(a),m_b(b){}int getA()const{return m_a;}int getB()const{return m_b;}Student(const Student& ) = delete;Student& operator=(const Student& );private:int m_a;int m_b;
};Student& Student::operator =(const Student& ) = delete;int main(int argc,char **argv)
{Student stu(1,2);cout<<stu.getA()<<endl; //1cout<<stu.getB()<<endl; //2Student stu1(3,4);stu1 = stu;//編譯報錯:Student.cpp:42:10: error: use of deleted function ‘Student& Student::operator=(const Student&)’std::cout<<is_pod<Student>::value<<std::endl;  //return 0;
}
  • Student& Student::operator =(const Student& ) = delete;

參考鏈接

  • C++11新特性之 “=default” 、“=delete”

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/447093.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/447093.shtml
英文地址,請注明出處:http://en.pswp.cn/news/447093.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C++學習 優雅的實現對象到文件的序列化/反序列化 關鍵字serialize

需要使用到序列化場景的需求 在寫代碼的過程中&#xff0c;經常會需要把代碼層面的對象數據保存到文件&#xff0c;而這些數據會以各種格式存儲&#xff0e;例如&#xff1a;json&#xff0c;xml&#xff0c;二進制等等&#xff0e;二進制&#xff0c;相比json&#xff0c;xml…

C++代碼注釋詳解

常用注釋語法 注釋寫在對應的函數或變量前面。JavaDoc類型的多行注釋風格如下&#xff1a; /** * 這里為注釋. */ 一般注釋中有簡要注釋和詳細注釋&#xff0c;簡要注釋有多種標識方式&#xff0c;這里推薦使用brief命令強制說明&#xff0c;例如&#xff1a;/** * brief 這里…

段錯誤:SIGSEGV

SIGSEGV是在訪問內存時發生的錯誤&#xff0c;它屬于內存管理的范疇 SIGSEGV是一個用戶態的概念&#xff0c;是操作系統在用戶態程序錯誤訪問內存時所做出的處理。 當用戶態程序訪問&#xff08;訪問表示讀、寫或執行&#xff09;不允許訪問的內存時&#xff0c;產生SIGSEGV。 …

web3 0.2.x 和 1.x.x版本之間的差異

版本差異 單位轉換 0.2.x web3.fromWei(13144321,ether) 1.x.x web3.utils.fromWei(13144321,ether)1.0以后的版本使用了大量的Promise&#xff0c;可以結合async/await使用&#xff0c;而0.20版本只支持回調函數

如何提高閱讀源碼的能力并且手撕源碼

怎么有效的手撕代碼呢&#xff1f; 把代碼跑起來把代碼一個片段拿出來使用畫出代碼運行的流程圖一行一行的搬運在看源碼的情況下寫出類似的demo

并發和并行的區別簡單介紹

并發和并行 并發是關于正確有效地控制對共享資源的訪問 同時完成多個任務。在開始處理其他任務之前&#xff0c;當前任務不需要完成。并發解決了阻塞發生的問題。當任務無法進一步執行&#xff0c;直到外部環境發生變化時才會繼續執行。最常見的例子是I/O&#xff0c;其中任務…

手撕源碼 alloc

怎么有效的手撕代碼呢&#xff1f; gnu gcc 2.9 的 內存池 把代碼跑起來把代碼一個片段拿出來使用畫出代碼運行的流程圖一行一行的搬運在看源碼的情況下寫出類似的demo 第三步&#xff1a; 第五步: // 這個頭文件包含一個模板類 allocator&#xff0c;用于管理內存的分配、…

Algorand的共識協議及其核心的優勢

Algorand 設計的初衷 Algorand 想解決的核心問題是&#xff1a;去中心化網絡中低延時&#xff08;Latency&#xff09;和高置信度&#xff08;Confidence&#xff09;之間的矛盾。其中&#xff0c;延時指從發起交易到確認交易所需要的時間&#xff1b;置信度指的是發出的交易不…

手撕源碼 SQL解析器 sqlparser

怎么有效的手撕代碼呢&#xff1f; 源代碼&#xff1a;https://github.com/hyrise/sql-parser 把代碼跑起來把代碼一個片段拿出來使用畫出代碼運行的流程圖一行一行的搬運在看源碼的情況下寫出類似的demo

針對Algorand所使用的密碼相關技術細節進行介紹

關鍵概念 VRF: 可驗證隨機函數。簡單來說是&#xff1a;vrf,Proof VRF(sk,seed)&#xff0c;sk為私鑰&#xff0c;seed為隨機種子&#xff1b;通過Verify(proof,pk,seed)驗證vrf的合法性。cryptographic sorition: 根據用戶本輪的VRF值&#xff0c;自身的權重以及公開的區塊鏈…

內存池的實現1 :重載

#ifndef KSTD_ALLOCATOR_H_ #define KSTD_ALLOCATOR_H_// 這個頭文件包含一個模板類 allocator&#xff0c;用于管理內存的分配、釋放&#xff0c;對象的構造、析構 // 暫不支持標準庫容器 todo::支持萃取#include <new> // placement new #include <cstddef>…

對于Algorand的介紹

介紹 Algorand具有能耗低、效率高、民主化、分叉概率極低、可拓展性好等優點&#xff0c;旨在解決現有區塊鏈項目存在的“不可能三角”&#xff08;高度可擴展的、安全的、去中心化&#xff09;問題。Algorand由MIT教授、圖靈獎得主Silvio Micali發起&#xff0c;擁有MIT區塊鏈…

內存池的實現2 類專用的內存適配器

B類增加了嵌入指針 #include<new> #include<ctime> #include<iostream> #include<cstdio> class A { public:A() {printf("next%p\n", next);};static void* operator new(size_t size);static void operator delete(void* phead);static i…

C++學習 高級編程

C 文件和流 到目前為止&#xff0c;目前使用最為廣泛的是 iostream 標準庫&#xff0c;它提供了 cin 和 cout 方法分別用于從標準輸入讀取流和向標準輸出寫入流。以下將介紹從文件讀取流和向文件寫入流。這就需要用到 C 中另一個標準庫 fstream&#xff0c;它定義了三個新的數…

內存池的實現3 固定大小的allocator單線程內存配置器

如果我們想使內存管理器用于其他大小不同的類該怎么辦呢&#xff1f;為每一個類重復管理邏輯顯然是對開發時間的不必要浪費。如果我們看一下前面內存管理器的實現&#xff0c;就會明顯地看出內存管理邏輯實際上獨立于特定的類 有關的是對象的大小一這是內存池模板實現的良好候選…

C++中文版本primer 第二章變量和基本類型 學習筆記

2.2變量 2.2.1 變量定義 列表初始化 定義一個名字為units_sold的int變量并初始化為0 int units_sold 0; int units_sold {0}; int units_sold{0}; int units_sold(0); C11 用花括號來初始化變量&#xff0c;上面這個步驟也稱之為列表初始化。這種初始化有一個重要的特點&…

內存池中的嵌入式指針

嵌入式指針 可以union改struct 內存分配后 next指針就沒用了 直接作為數據空間比較省內存 因為對指針指向的內存存儲的時候 編譯器是不管你是什么類型的 &#xff0c;這里有道練習題可以對指針的概念稍微理解一下&#xff1a; #include <iostream> using std::cout; us…

C++ 標準程序庫std::string 詳解

現在一般不再使用傳統的char*而選用C標準程序庫中的string類&#xff0c;是因為string標準程序和char*比較起來&#xff0c;不必擔心內存是否足夠、字符串長度等等&#xff0c;而且作為一個類出現&#xff0c;集成的操作函數足以完成大多數情況下(甚至是100%)的需要。比如&…

內存池的實現4 alloc內存池

alloc 內存池 優點: &#xff1a;本質是定長內存池的改進&#xff0c;分配和釋放的效率高。可以解決一定長度內存分配的問題。 缺點 &#xff1a;存在內碎片的問題&#xff0c;且將一塊大內存切小以后&#xff0c;申請大內存無法使用&#xff0c;別的FreeList掛了很多空閑的內存…