C++之面向?qū)ο蟮恼Z法筆記

前言

最近項(xiàng)目在開發(fā)涉及到的C++內(nèi)容相對比較多,整理一下,過程中用到的C++面向?qū)ο蟮恼Z法筆記

正文

知識(shí)點(diǎn)的概要

  • C++ 類 & 對象
  • 值傳遞&引用傳遞
  • 拷貝構(gòu)造函數(shù)
  • 繼承& 多態(tài)
  • 友元
  • 模板
  • 類型轉(zhuǎn)換
  • 異常捕獲

類& 對象

  • C++類定義:本質(zhì)上是定義一個(gè)數(shù)據(jù)類型的合集
    類定義是以關(guān)鍵字 class 開頭,后跟類的名稱。類的主體是包含在一對花括號(hào);
class Teacher
{
public:
    Teacher(); //構(gòu)造函數(shù) (malloc)
    Teacher(int age, char * name); //構(gòu)造函數(shù) (malloc)
    ~Teacher();  //析構(gòu)函數(shù) 釋放在構(gòu)造函數(shù)里面動(dòng)態(tài)申請的內(nèi)存 (free)

    void setAge(int age);
    int getAge();
    void setName(char *name);
    char* getName();

private:
    int age;
    char *name;
};
  • C++對象的定義
    聲明類的對象,就像聲明基本類型的變量一樣
Teacher teacher1;  //無參構(gòu)造函數(shù),也可以Teacher teacher1 = Teacher();
Teacher teacher2(28, "kevin");  //有參構(gòu)造函數(shù),創(chuàng)建對象, 也可以Teacher teacher2 = Teacher(28, "kevin");
Teacher *p_teacher = new Teacher(29,"chenyu");  //對象指針,創(chuàng)建可直接new關(guān)鍵字或者下面的方式
Teacher *p_teacher2;
p_teacher2 = &teacher1;
  • 完整的例子
    Teacher.h:
#pragma once
class Teacher
{
public:
    Teacher(); //構(gòu)造函數(shù) (malloc)
    Teacher(int age, char * name); //構(gòu)造函數(shù) (malloc)
    ~Teacher();  //析構(gòu)函數(shù) 釋放在構(gòu)造函數(shù)里面動(dòng)態(tài)申請的內(nèi)存 (free)

    void setAge(int age);
    int getAge();
    void setName(char *name);
    char* getName();
private:

    int age;
    char *name;

};

Teacher.cpp:

#include "Teacher.h"
#include <iostream>

//c++ 標(biāo)準(zhǔn)庫的命名空間
using namespace std;

Teacher::Teacher()
{
    cout << " Teacher 構(gòu)造函數(shù)  地址:" << this << endl;
}

Teacher::Teacher(int age, char * name) 
{
    cout << " Teacher 構(gòu)造函數(shù)  地址:" << this << endl;
    this->age = age;
    this->name = name;
    cout << " Teacher age :" << age << " name :"<< name << endl;
}


Teacher::~Teacher()
{
    cout << " Teacher 析構(gòu)函數(shù)  地址:" << this << endl;
}


void Teacher::setAge(int age) {
    cout << "Teacher setAge is " << age << endl;
    this->age = age;
}
int Teacher::getAge() {
    return this->age;
}
void Teacher::setName(char *name) {
    cout << " Teacher setName is " << name << endl;
    this->name = name;
}
char* Teacher::getName() {
    return this->name;
}

main.cpp:

#include "Teacher.h"
#include "Student.h"
#include <iostream>

using namespace std;

void fun() {
    Teacher teacher1;  //無參構(gòu)造函數(shù),也可以Teacher teacher1 = Teacher();
    Teacher teacher2(28, "kevin");  //有參構(gòu)造函數(shù),創(chuàng)建對象, 也可以Teacher teacher2 = Teacher(28, "kevin");
    Teacher *p_teacher = new Teacher(29,"chenyu");  //對象指針,創(chuàng)建是需要new關(guān)鍵字

    teacher1.setAge(31);
    teacher1.setName("jason");

    cout << "teacher1 name: " << teacher1.getName() << endl;
    cout << "teacher1 age: " << teacher1.getAge() << endl;

    cout << "teacher2 name: " << teacher2.getName() << endl;
    cout << "teacher2 age: " << teacher2.getAge() << endl;

    cout << "p_teacher name: " << p_teacher->getName() << endl;
    cout << "p_teacher age: " << p_teacher->getAge() << endl;

    //及時(shí)釋放
    delete p_teacher;
    p_teacher = nullptr;

}

void main() {
    fun();
    system("pause");
}

值傳遞&引用傳遞

在函數(shù)調(diào)用中,如果需要將類的對象作為形參,傳入到某個(gè)函數(shù)進(jìn)行調(diào)用,這種情況分為值傳遞和引用傳遞。

  • 值傳遞
//為什么這里只調(diào)用了析構(gòu)函數(shù),沒有調(diào)用構(gòu)造函數(shù)?
//值傳遞 存在值拷貝
void funValuePass(Teacher teacher) 
{
    teacher.setAge(31);
    teacher.setName("liuyan"); 

    cout << "funValuePass teacher name: " << teacher.getName() << endl;
    cout << "funValuePass teacher age: " << teacher.getAge() << endl;
}
  • 引用傳遞
    什么是引用?

引用是原變量的一個(gè)別名.
n 相當(dāng)于m 的別名(綽號(hào)),對n 的任何操作就是對m 的操作。例如有個(gè)人叫是JackMa,綽號(hào)是“馬爸爸”。說“馬爸爸”怎么怎么的,其實(shí)就是在說JackMa。所以n 既不是m 的拷貝,也不是指向m 的指針,其實(shí)n就是m 它自己。
c++中的引用 (就是再堆中分配空間)

堆空間內(nèi)存分配.jpg

堆(heap)空間:
動(dòng)態(tài)分配的內(nèi)存(malloc 等api 分配在堆空間, c++中的new)
堆用于存放進(jìn)程運(yùn)行時(shí)動(dòng)態(tài)分配的內(nèi)存段,可動(dòng)態(tài)擴(kuò)張或縮減。堆中內(nèi)容是匿名的,不能按名字直接訪問,只能通過指針間接訪問。
棧(stack)空間:
局部變量、函數(shù)參數(shù)、返回地址等(系統(tǒng)自動(dòng)分配的臨時(shí)內(nèi)存)Linux有專門的寄存器管理?xiàng)?nèi)存(效率高)
.bss段
未初始化或初值為0的全局變量和靜態(tài)局部變量
.data段
已初始化且初值非0的全局變量和靜態(tài)局部變量
.text段
可執(zhí)行代碼、只讀變量,全局靜態(tài)變量

//引用傳遞
//c++ 引用 是內(nèi)存空間的別名 不存在拷貝 只傳遞內(nèi)存別名
void funRefPass(Teacher &teacher) {

    teacher.setAge(32);
    teacher.setName("Chen"); 

    cout << "funRefPass teacher name: " << teacher.getName() << endl;
    cout << "funRefPass teacher age: " << teacher.getAge() << endl;
}
  • 引用和指針的區(qū)別
  1. 指針是一個(gè)實(shí)體,而引用僅是個(gè)別名;
  2. 引用使用時(shí)無需解引用(*),指針需要解引用;
  3. 引用只能在定義時(shí)被初始化一次,之后不可變;指針可變; 引用“從一而終” 。
  4. 引用沒有 const,指針有 const,const 的指針不可變;
  5. 引用不能為空,指針可以為空;
  6. “sizeof 引用”得到的是所指向的變量(對象)的大小,而“sizeof 指針”得到的是指針本身(所指向的變量或?qū)ο蟮牡刂罚┑拇笮。?/li>
  7. 引用是面向?qū)ο蟮母拍?,指針是面向過程種的概念,C++能夠混編C語言,所以C++支持指針
  • 代碼調(diào)用
    值引用:
void main() {

    Teacher teacher;

    teacher.setAge(24);
    teacher.setName("lily");
        //值傳遞
    funValuePass(teacher);
        //這邊值沒有發(fā)生變化
    cout << "teacher name: " << teacher.getName() << endl;
    cout << "teacher age: " << teacher.getAge() << endl; 
    system("pause");
}

輸出結(jié)果:


值傳遞的結(jié)果.png

引用傳遞:

void main() {

    Teacher teacher;

    teacher.setAge(24);
    teacher.setName("lily");
        //引用傳遞
    funRefPass(teacher);
       //這邊值已經(jīng)發(fā)生變化
    cout << "teacher name: " << teacher.getName() << endl;
    cout << "teacher age: " << teacher.getAge() << endl; */
    system("pause");
}

輸出結(jié)果:


引用傳遞的結(jié)果.png

拷貝構(gòu)造函數(shù)

拷貝構(gòu)造函數(shù)是一種特殊的構(gòu)造函數(shù),它在創(chuàng)建對象時(shí),是使用同一類中之前創(chuàng)建的對象來初始化新創(chuàng)建的對象。
拷貝構(gòu)造函數(shù)通常用于:

  1. 通過使用另一個(gè)同類型的對象來初始化新創(chuàng)建的對象。
  2. 復(fù)制對象把它作為參數(shù)傳遞給函數(shù)。
  3. 復(fù)制對象,并從函數(shù)返回這個(gè)對象。
    對拷貝,C++ 的String源碼,最能體現(xiàn)。
    舉個(gè)例子區(qū)分賦值和拷貝
String  s1("aaa");
String  s2("bbb");
String  str = s1; //這個(gè)就是調(diào)用了拷貝構(gòu)造函數(shù),等同String str(s1);
             str  = s2 //這個(gè)是調(diào)用賦值函數(shù)

拷貝分為 淺拷貝深拷貝
淺拷貝:位拷貝,拷貝構(gòu)造函數(shù),賦值重載,多個(gè)對象共用同一塊資源,同一塊資源釋放多次,崩潰或者內(nèi)存泄漏
深拷貝:每個(gè)對象共同擁有自己的資源,必須顯式提供拷貝構(gòu)造函數(shù)和賦值運(yùn)算符

  • 淺拷貝
Student::Student(const Student &student) {
  cout << " MyStudent 拷貝構(gòu)造函數(shù)  地址:" << this << endl;
  this->age = student.age;
  this->name = student.name;
  this->teacherName = student.teacherName;
}
  • 深拷貝
Student::Student(const Student &student) {
    cout << " Student 深拷貝構(gòu)造函數(shù)  地址:" << this << endl;
    int len = strlen(student.name);
    this->name = (char *)malloc(len + 1);
    strcpy(this->name, student.name);

    len = strlen(student.teacherName);
    this->teacherName = (char *)malloc(len + 1);

    strcpy(this->teacherName, student.teacherName);
}
  • 完整的例子
    Student.h:
#pragma once
class Student
{
public:
    Student(int age, char *name, char *teacherName);
    ~Student();

/*private:
    //重寫默認(rèn)的拷貝構(gòu)造函數(shù) 這種方案不常用
    MyStudent(const MyStudent &student);*/
    Student::Student(const Student &student);
public:
    int age;
    char *name;
    char *teacherName;

};

Student.cpp:

#include "Student.h"
#include <iostream>

using namespace std;

Student::Student(int age, char *name, char *teacherName)
{
    cout << " Student 構(gòu)造函數(shù)  地址:" << this << endl;
    int len = strlen(name);
    this->name = (char *)malloc(len + 1);
    strcpy(this->name, name);

    len = strlen(teacherName);
    this->teacherName = (char *)malloc(len + 1);

    strcpy(this->teacherName, teacherName);
}


Student::~Student()
{
    cout << " Student 析構(gòu)函數(shù) 地址:" << this << endl;
    free(this->name); //拷貝構(gòu)造函數(shù)釋放野指針出錯(cuò)
    free(this->teacherName);
}


//默認(rèn)拷貝構(gòu)造函數(shù) 實(shí)現(xiàn)淺拷貝
/*Student::Student(const Student &student) {

cout << " MyStudent 拷貝構(gòu)造函數(shù)  地址:" << this << endl;
this->age = student.age;
this->name = student.name;
this->teacherName = student.teacherName;

}*/

//覆蓋默認(rèn)的拷貝構(gòu)造函數(shù) 實(shí)現(xiàn)深拷貝
Student::Student(const Student &student) {

    cout << " Student 深拷貝構(gòu)造函數(shù)  地址:" << this << endl;
    int len = strlen(student.name);
    this->name = (char *)malloc(len + 1);
    strcpy(this->name, student.name);

    len = strlen(student.teacherName);
    this->teacherName = (char *)malloc(len + 1);

    strcpy(this->teacherName, student.teacherName);

}

main.cpp:

// 1. 淺拷貝
// 2.避免淺拷貝引發(fā)野指針問題
//   2.1 深拷貝
//  2.2 私有化拷貝構(gòu)造函數(shù) 
void copyTest() {
    Student student = Student(21, "Jake", "Jhone");
    cout << "setFunX student1 name: " << student.name << endl;
    cout << "setFunX student1 age: " << student.age << endl;
    cout << "setFunX student1 age: " << student.teacherName << endl;
    Student st2 = student;  // 這里也調(diào)用了拷貝構(gòu)造函數(shù)
    cout << "setFunX student2 name: " << st2.name << endl;
    cout << "setFunX student2 age: " << st2.age << endl;
    cout << "setFunX student2 age: " << st2.teacherName << endl;
}

void main() {
    copyTest();
    system("pause");
}

繼承& 多態(tài)

繼承

當(dāng)創(chuàng)建一個(gè)類時(shí),您不需要重新編寫新的數(shù)據(jù)成員和成員函數(shù),只需指定新建的類繼承了一個(gè)已有的類的成員即可。這個(gè)已有的類稱為基類,新建的類稱為派生類。
C++ 繼承的繼承指的就是基類和派生類的關(guān)系。

  • 代碼:

基類Plane.h

#pragma once
#include <string>

using namespace std;

class Plane
{
public:
    Plane();
    Plane(std::string name, int year);
    ~Plane();

    void fly();
    void land();
    void printf();
protected:
    std::string name;
    int year;
};

基類Plane.cpp

#include "Plane.h"
#include <iostream>

using namespace std;

Plane::Plane() :name("灣流"), year(1991) {
    cout << "Plane  無參構(gòu)造函數(shù)" << name << year << endl;
}

Plane::Plane(std::string name, int year) :name(name), year(year) {
    cout << "Plane 構(gòu)造函數(shù)" << name << year << endl;
}

Plane::~Plane()
{
    cout << "Plane 析構(gòu)函數(shù)" << endl;
}

void Plane::fly() {
    cout << "Plane fly" << endl;
}

void Plane::land() {
    cout << "Plane land" << endl;
}

void Plane::printf() {
    cout << "Plane printf " << "name = " << name << " year = " << year << endl;
}

派生類Jet.h:

#include "Plane.h"

class Jet : public Plane
{
public:
    Jet();
    Jet(std::string name, int year);
    ~Jet();

    void fly();

    void land();
    void test();
};

派生類Jet.cpp:

#include "Jet.h"
#include <iostream>

using namespace std;

Jet::Jet() {
    cout << "Jet  無參構(gòu)造函數(shù)" << name << year << endl;
}

Jet::Jet(std::string name, int year) {
    cout << "Jet  構(gòu)造函數(shù)" << name << year << endl;
}


Jet::~Jet() {
    cout << "Jet 析構(gòu)函數(shù)" << endl;
}

//重寫
void Jet::fly() {
    cout << "Jet fly" << endl;
}

void Jet::land() {
    cout << "Jet land" << endl;
}

void Jet::test() {
}

調(diào)用類main.cpp:


//1. 先調(diào)用父類的構(gòu)造函數(shù)
//2.釋放時(shí)先調(diào)用子類的析構(gòu)函數(shù)

//子類沒有 就使用父類的方法
//子類有實(shí)現(xiàn),就是用子類的重寫
//父類型的引用 賦值子類型的對象 方法都是父類型中的方法
void funExtends() {
    Jet jet;
    //jet.fly();

    //jet.Plane::fly();
    Plane *pl = &jet;
    pl->fly();

    Plane &p2 = jet;
    p2.fly();
}

void main() {
    funExtends();
    system("pause");
}

輸出結(jié)果:父類型的引用 賦值子類型的對象 方法都是父類型中的方法


輸出結(jié)果.png

輸出的結(jié)果,調(diào)用的還是父類的方法,不是子類的方法,上面的情況明顯不是我們想要的結(jié)果,怎么解決呢?
方法:使用虛函數(shù) 讓派生類類 重載父類方法
在Plane.h中,將fly和land兩個(gè)方法添加virtual進(jìn)行修飾

    virtual void fly();
    virtual void land();

再次輸出結(jié)果:


期望的結(jié)果.png
  • 繼承類型
    如下代碼:A繼承基類B的時(shí)候,帶著修飾符,繼承的修飾符有三種:public、protected、private。
class A : public B{};

我們幾乎不使用 protected 或 private 繼承,通常使用 public 繼承。當(dāng)使用不同類型的繼承時(shí),遵循以下幾個(gè)規(guī)則:

繼承類型 說明
public 當(dāng)一個(gè)類派生自公有基類時(shí),基類的公有成員也是派生類的公有成員,基類的保護(hù)成員也是派生類的保護(hù)成員,基類的私有成員不能直接被派生類訪問,但是可以通過調(diào)用基類的公有和保護(hù)成員來訪問。
protected 當(dāng)一個(gè)類派生自保護(hù)基類時(shí),基類的公有和保護(hù)成員將成為派生類的保護(hù)成員。
private 當(dāng)一個(gè)類派生自私有基類時(shí),基類的公有和保護(hù)成員將成為派生類的私有成員。
  • 多繼承
    多繼承即一個(gè)子類可以有多個(gè)父類,它繼承了多個(gè)父類的特性。類似一個(gè)人可以有多個(gè)師傅;
class A{};
class B{};
class C: public A, public B{};

多態(tài)

  • 概念
    多態(tài)按字面的意思就是多種形態(tài)。當(dāng)類之間存在層次結(jié)構(gòu),并且類之間是通過繼承關(guān)聯(lián)時(shí),就會(huì)用到多。C++ 多態(tài)意味著調(diào)用成員函數(shù)時(shí),會(huì)根據(jù)調(diào)用函數(shù)的對象的類型來執(zhí)行不同的函數(shù)。
    C++的多態(tài)性用一句話概括就是:在基類的函數(shù)前加上virtual關(guān)鍵字,在派生類中重寫該函數(shù),運(yùn)行時(shí)將會(huì)根據(jù)對象的實(shí)際類型來調(diào)用相應(yīng)的函數(shù)。如果對象類型是派生類,就調(diào)用派生類的函數(shù);如果對象類型是基類,就調(diào)用基類的函數(shù)。
  • 實(shí)例解釋
    以上面的plane類為例,jet繼承了Plane,是plane的派生類,在進(jìn)行創(chuàng)建一個(gè)Copter派生類 繼承Plane基類
    Copter.h:
#include "Plane.h"

class Copter : public Plane
{
public:
    Copter();
    Copter(std::string name, int year);
    ~Copter();

    void fly();

    void land();

};

Copter.cpp:

#include "Copter.h"
#include <iostream>

using namespace std;

Copter::Copter() {
    cout << "Copter  無參構(gòu)造函數(shù)" << name << year << endl;
}

Copter::Copter(std::string name, int year) {
    cout << "Copter  構(gòu)造函數(shù)" << name << year << endl;
}

Copter::~Copter() {
    cout << "Copter 析構(gòu)函數(shù)" << endl;
}

//重寫
void Copter::fly() {
    cout << "Copter fly" << endl;
}

void Copter::land() {
    cout << "Copter land" << endl;
}

調(diào)用

    Plane *plane;
    Jet jet("波音707", 1997);
    Copter copter("絕影", 2005);

    // 存儲(chǔ)Jet的地址
    plane = &jet;
    // 調(diào)用Jet的函數(shù) fly
    plane->fly();

    // 存儲(chǔ)copter的地址
    plane = &copter;
    // 調(diào)用Copter的函數(shù) fly
    plane->fly();

編譯輸出結(jié)果:


image.png
  • 分類
    虛函數(shù) (c++多態(tài)的基礎(chǔ)) 增加程序的擴(kuò)展性
    動(dòng)態(tài)多態(tài): 程序運(yùn)行過程中,覺得哪一個(gè)函數(shù)被調(diào)用
    靜態(tài)多態(tài): 重載(函數(shù)名稱相同,參數(shù)不同,面向?qū)ο蟮奶匦?,c 中不行)

  • 發(fā)生動(dòng)態(tài)多態(tài)的條件:

  1. 繼承
  2. 父類的引用或者指針指向子類的對象
  3. 函數(shù)的重寫

重載(overload):在相同作用域內(nèi),函數(shù)名稱相同,參數(shù)或常量性(const)不同的相關(guān)函數(shù)稱為重載。重載函數(shù)之間的區(qū)分主要在參數(shù)和常量性(const)的不同上,若僅僅是返回值或修飾符 virtual,public/protected/private的不同不被視為重載函數(shù)(無法通過編譯)。不同參數(shù)是指參數(shù)的個(gè)數(shù)或類型不同,而類型不同是指各類型之間不能進(jìn)行隱身類型轉(zhuǎn)換或不多于一次的用戶自定義類型轉(zhuǎn)換(關(guān)于類型轉(zhuǎn)換,請參考前文:類型轉(zhuǎn)型(Type Casting))。當(dāng)調(diào)用發(fā)生時(shí),編譯器在進(jìn)行重載決議時(shí)根據(jù)調(diào)用所提供的參數(shù)來選擇最佳匹配的函數(shù)。

重寫(override):派生類重寫基類中同名同參數(shù)同返回值的函數(shù)(通常是虛函數(shù),這是推薦的做法)。同樣重寫的函數(shù)可以有不同的修飾符virtual,public/protected/private。

  • 純虛函數(shù)(抽象類)
  1. 當(dāng)一個(gè)類具有一個(gè)純虛函數(shù),這個(gè)類就是抽象類
  2. 抽象類不能實(shí)例化對象
  3. 子類繼承抽象類,必須要實(shí)現(xiàn)純虛函數(shù),如果沒有,子類也是抽象類
    關(guān)于虛函數(shù)和純虛函數(shù)的具體:https://www.runoob.com/w3cnote/cpp-virtual-functions.html

友元

  • 概念
    類的友元函數(shù)是定義在類外部,但有權(quán)訪問類的所有私有(private)成員和保護(hù)(protected)成員。盡管友元函數(shù)的原型有在類的定義中出現(xiàn)過,但是友元函數(shù)并不是成員函數(shù)。采用friend 關(guān)鍵字 表示友元。
  • 友元的兩種表現(xiàn)形式
  1. 友元函數(shù)
  2. 友元類
  • 實(shí)例
class Girl
{
public:
    //友元函數(shù)不能使用this
    friend void modify(Girl *girl, int age);   //聲明的友元函數(shù)
    friend class Boy;    //聲明的友元類

    //friend void Boy::introduce();

    void tell();

private:
    int age = 16;
    string name = "大笑";
};

//girl class的函數(shù)實(shí)現(xiàn)
void Girl::tell() {

    cout << "age == " << age << endl;
}

class Boy
{
public:
    Boy(Girl girl) {
        this->girl = girl;

    }

    ~Boy() {

    }

    void changGirl() {
        girl.age = 28;
        girl.name = "vava";
    }

    //已經(jīng)聲明為友元函數(shù) 可以訪問和修改私有屬性s
    void introduce() {
        cout << "My Girl friend age : " << girl.age << "name = " << girl.name << endl;
    }

public:
    Girl girl;
};

//外部實(shí)現(xiàn)
void modify(Girl *girl, int age) {

    girl->age = age;
}

void main() {
    /*Girl *girl = new Girl();

    modify(girl, 31);

    girl->tell();

    delete girl;*/

    Girl girl;
    Boy boy = Boy(girl);

    boy.introduce();

    boy.changGirl();
    boy.girl.tell();
    boy.introduce();

    system("pause");
}

輸出的結(jié)果


友元類.png

友元函數(shù).png

模板

模板是泛型編程的基礎(chǔ),泛型編程即以一種獨(dú)立于任何特定類型的方式編寫代碼。

  • 表現(xiàn)形式
  1. 模板函數(shù)
  2. 模板類
  • 實(shí)例
    模板函數(shù)
template <typename T>
void myswap(T& a, T& b) {
    T tmp = 0;
    tmp = a;
    a = b;
    b = tmp;
    cout << "myswap T" << endl;
}

void main() {

    int a = 999;
    int b = 666;

    myswap(a,b);
    cout << "a = "<< a << "b = " <<b << endl;

    char c = '9';
    char v = '6';

    myswap(c, v);

    cout << "c = " << c << "v = " << v << endl;

輸出結(jié)果:


模板函數(shù).png

模板類

template<class  T>
class  A
{
public:
    A(T a) {
        this->a = a;
    }
     ~A() {
     }

protected:
    T a;
};

template <class  T>
class C : public A<T>
{
public:
    
    C(T c, T a) : A<T>(a) {
        this->c = c;
    }

    void tell() {
        cout << "a : " << a << "c " << c << endl;
    }
private:
    T c;
};

void main() {
 C<int>  c(1,2);
 c.tell();
}

輸出結(jié)果:


模板類.png

類型轉(zhuǎn)換

C++ 常見的幾種類型轉(zhuǎn)換

  1. static_cast 普通值類型轉(zhuǎn)換
  2. const_cast 去常量
  3. dynamic_cast 基類和派生類之間的轉(zhuǎn)換
  4. reinterpret_cast 不通用 不常用 函數(shù)指針的轉(zhuǎn)換 (一般在Void * 之間轉(zhuǎn))
    前三種是通用,常用的,第四種屬于不通用,不常用
  • 實(shí)例
void func(const char c[]) {
    //c[1] = 'a';
    //去掉const 關(guān)鍵字
    char* c_p = const_cast<char *>(c);
    c_p[1] = 'X';
}

class Person {

public:
    virtual void print() {
        cout << "人" << endl;
    }
};

class Man : public Person
{
public:
    void print() {
        cout << "男人" << endl;
    }

    void chasing() {
        cout << "泡妞" << endl;
    }
};

class Woman :public Person
{
public:
    
    void print() {
        cout << "女人" << endl;
    }

    void createBaby() {
        cout << "造小孩" << endl;
    }
};

void funx(Person* obj) {

    //Man *m = (Man *)obj;
    //m->chasing();

    Man *m = dynamic_cast<Man*>(obj);
    if (m != nullptr) {
        m->chasing();
    }
    else {
        cout << "還需要去趟泰國" << endl;
    }
}

void main() {

    int i = 8;
    double d = 9.5;

    //i = (int)d;
    i = static_cast<int> (d);

    char c[] = "hello";
    cout << "c = " << c << endl;
    func(c);
    cout << "c = " << c << endl;

        Man *m = new Man();
    funx(m);

    system("pause");
}

異常捕獲

異常是程序在執(zhí)行期間產(chǎn)生的問題;
異常提供了一種轉(zhuǎn)移程序控制權(quán)的方式。C++ 異常處理涉及到三個(gè)關(guān)鍵字:try、catch、throw。 類Java的異常。

  1. throw: 當(dāng)問題出現(xiàn)時(shí),程序會(huì)拋出一個(gè)異常。這是通過使用 throw 關(guān)鍵字來完成的。
  2. catch: 在您想要處理問題的地方,通過異常處理程序捕獲異常。catch 關(guān)鍵字用于捕獲異常。
  3. try: try 塊中的代碼標(biāo)識(shí)將被激活的特定異常。它后面通常跟著一個(gè)或多個(gè) catch 塊。
  • 實(shí)例
void main() {
    try
    {
        int age = 300;
        if (age > 200) {
            throw "xxx";
        }
    }
    catch (int a)
    {
        cout << "int 異常"<<endl;
    }
    catch (char * b) {
        cout << "char b" <<b << endl;
    }
    system("pause");
}

輸出結(jié)果:


異常.png
  • 定義新的異常
class NullPointerException : public exception {

public:

    NullPointerException(char * msg) :exception(msg) {
        
    }
};

void main() {
    try
    {
        int age = 300;
        if (age > 200) {
            throw NullPointerException("pgone");
        }
    }
    catch (int a)
    {
        cout << "int 異常" << endl;
    }
    catch (char * b) {
        cout << "char b" << b << endl;
    }
    catch (NullPointerException msg) {
        
    }
    system("pause");
}

筆記就做到這了。如果有什么問題歡迎指出。

參考文獻(xiàn)

https://www.runoob.com/w3cnote/cpp-virtual-functions.html
https://blog.csdn.net/qq_39477053/article/details/80322260
https://blog.csdn.net/BLUCEJIE/article/details/104474930

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容