NDK開(kāi)發(fā)---C++學(xué)習(xí)(三):類(lèi)與函數(shù)(上)

前言

前面簡(jiǎn)單介紹了C++中的基本知識(shí)和引用,本篇博客將介紹C++中的類(lèi)與函數(shù),分別是成員函數(shù)、無(wú)參構(gòu)造函數(shù)、有參構(gòu)造函數(shù)、析構(gòu)函數(shù)、拷貝構(gòu)造函數(shù)等。

成員函數(shù)

類(lèi)的成員函數(shù)有兩種定義:一種是在聲明類(lèi)時(shí)就給出成員函數(shù)的定義;另一種是在聲明類(lèi)時(shí),只聲明成員函數(shù)的原型,然后在類(lèi)的外部定義成員函數(shù),其定義方法是:

返回類(lèi)型 類(lèi)名::成員函數(shù)名(參數(shù)表)

其中,::是域限定符,用于說(shuō)明成員函數(shù)名是指定類(lèi)名中的一個(gè)函數(shù)。這里我將就第二種舉例子如下:
首先我們創(chuàng)建一個(gè)頭文件MyTeacher.h

//防止被重復(fù)引用
#pragma once;   

class MyTeacher {
private:
    char* name;
    int age;
public:
    void setName(char* name);
    char* getName();
    void setAge(int age);
    int getAge();
};

頭文件中定義了類(lèi)MyTeacher,聲明了四個(gè)函數(shù),#pragma once防止被重復(fù)引用。
再創(chuàng)建一個(gè)C++文件,用于上面四個(gè)函數(shù)的定義

#include "MyTeacher.h"

void MyTeacher::setName(char* name) {
    this->name = name;
}
char* MyTeacher::getName() {
    return this->name;
}
void MyTeacher::setAge(int age) {
    this->age = age;
}
int MyTeacher::getAge() {
    return this->age;
}

最后我們?cè)诹硪粋€(gè)C++文件中去使用

#include<iostream>
#include<stdarg.h>
#include "MyTeacher.h"
using namespace std;
void main() {
    MyTeacher t;
    t.setName("john");
    cout << t.getName() << endl;

    getchar();
}

運(yùn)行打印結(jié)果:

john

類(lèi)成員函數(shù)的第二種定義方式在C++中是比較普遍的,需要了解一下。

無(wú)參構(gòu)造函數(shù)

#include<iostream>
#include<stdarg.h>
using namespace std;
class Teacher {
private:
    char* name;
    int age;
public:
    //無(wú)參構(gòu)造函數(shù)(有默認(rèn)的無(wú)參構(gòu)造函數(shù),如果添加了,就會(huì)覆蓋默認(rèn)的無(wú)參構(gòu)造函數(shù))
    Teacher() {
        cout << "無(wú)參構(gòu)造函數(shù)" << endl;
    }
};

void main() {
    Teacher t1;

    getchar();
}

運(yùn)行打印結(jié)果:

無(wú)參構(gòu)造函數(shù)

有參構(gòu)造函數(shù)

添加有參構(gòu)造函數(shù),將無(wú)參構(gòu)造函數(shù)注釋

//有參構(gòu)造函數(shù)會(huì)覆蓋默認(rèn)的無(wú)參構(gòu)造函數(shù)
Teacher(char* name, int age) {
        this->name = name;
        this->age = age;
        cout << "有參構(gòu)造函數(shù)" << endl;
}

main函數(shù)中調(diào)用,將無(wú)參函數(shù)的調(diào)用注釋

Teacher t2("john", 23);
//有參構(gòu)造函數(shù)的另一種寫(xiě)法
//Teacher t2 = Teacher("john", 23);

運(yùn)行打印輸出結(jié)果為:

有參構(gòu)造函數(shù)

析構(gòu)函數(shù)

添加析構(gòu)函數(shù),將有參構(gòu)造函數(shù)注釋

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

編寫(xiě)一個(gè)函數(shù),創(chuàng)建Teacher的引用

void func() {
    Teacher t3;
}

main函數(shù)中調(diào)用func函數(shù),將有參構(gòu)造函數(shù)注釋

func();

運(yùn)行打印結(jié)果為:

析構(gòu)函數(shù)

當(dāng)對(duì)象要被釋放時(shí),析構(gòu)函數(shù)會(huì)被調(diào)用,此例中的Teacher t3要被釋放時(shí),析構(gòu)函數(shù)被調(diào)用。析構(gòu)函數(shù)的作用就是做一些善后處理工作。接下來(lái)我們來(lái)模擬析構(gòu)函數(shù)的善后處理工作。
將無(wú)參構(gòu)造函數(shù)打開(kāi),并修改如下:

Teacher() {
        this->name = (char*)malloc(100);
        strcpy(this->name, "john");
        cout << "無(wú)參構(gòu)造函數(shù)" << endl;
    }

析構(gòu)函數(shù)將this->name內(nèi)存通過(guò)free釋放

~Teacher(){
        free(this->name);
        cout << "析構(gòu)函數(shù)" << endl;
}

運(yùn)行錯(cuò)誤,在頭文件上方添加

#define _CRT_SECURE_NO_WARNINGS

運(yùn)行打印結(jié)果為:

無(wú)參構(gòu)造函數(shù)
析構(gòu)函數(shù)

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

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
class Teacher {
private:
    char* name;
    int age;
public:
    Teacher(char* name, int age) {
        this->name = name;
        this->age = age;
        cout << "有參構(gòu)造函數(shù)" << endl;
    }
    //拷貝構(gòu)造函數(shù)(值拷貝)
    //默認(rèn)拷貝構(gòu)造函數(shù)就是值拷貝
    Teacher(const Teacher &obj) {
        this->name = obj.name;
        this->age = obj.age;
        cout << "拷貝構(gòu)造函數(shù)" << endl;
    }

    void myPrintf() {
        cout << this->name << "," << this->age << endl;
    }
};

void main() {
    Teacher t1 = Teacher("john", 23);
    Teacher t2 = t1;
    t2.myPrintf();

    getchar();
}

拷貝構(gòu)造函數(shù)的參數(shù)其實(shí)就是常引用,這下是不是對(duì)常引用的應(yīng)用又了解了一波呢?默認(rèn)拷貝構(gòu)造函數(shù)就是值拷貝,也就是說(shuō)如果不寫(xiě)任何拷貝函數(shù),默認(rèn)就是值拷貝,值拷貝又名淺拷貝。
拷貝構(gòu)造函數(shù)被調(diào)用的場(chǎng)景:

1.聲明時(shí)賦值
Teacher t2 = t1;
2.作為參數(shù)傳入,實(shí)參給形參賦值
3.作為函數(shù)返回值返回,給變量初始化賦值

淺拷貝問(wèn)題

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
class Teacher {
private:
    char* name;
    int age;
public:
    Teacher(char* name, int age) {
        this->name = (char*)malloc(100);
        strcpy(this->name, name);
        this->age = age;
        cout << "有參構(gòu)造函數(shù)" << endl;
    }

    ~Teacher() {
        //釋放內(nèi)存
        free(this->name);
        cout << "析構(gòu)函數(shù)" << endl;
    }
};

void func() {
    Teacher t1("jonh", 23);
    Teacher t2 = t1;
}

void main() {
    func();

    getchar();
}

這里有參函數(shù)中通過(guò)動(dòng)態(tài)內(nèi)存的方式給this->name給予內(nèi)存空間,在析構(gòu)函數(shù)中釋放內(nèi)存。運(yùn)行出現(xiàn)錯(cuò)誤,錯(cuò)誤信息大意就是程序試圖刪除一個(gè)空指針,結(jié)果為:

有參構(gòu)造函數(shù)
析構(gòu)函數(shù)

我們來(lái)分析一下執(zhí)行的流程,首先執(zhí)行t1的有參構(gòu)造函數(shù),給t1this->name賦予內(nèi)存空間,然后執(zhí)行默認(rèn)的淺拷貝,上面有說(shuō)過(guò)淺拷貝其實(shí)就是值拷貝,而指針的值就是地址,所以會(huì)將t2this->name賦予剛才一樣的內(nèi)存空間。這時(shí)候func函數(shù)執(zhí)行完,將釋放內(nèi)部的局部變量,首先釋放的是t2,而不是t1,對(duì)于此處不相信的同學(xué)可以在func函數(shù)中分別對(duì)t1t2age賦值為1,2,然后在析構(gòu)函數(shù)中打印age的值,就可以知曉釋放的先后順序。言歸正傳,首先釋放t2,將那塊相同的內(nèi)存空間釋放,接下來(lái)再去調(diào)用析構(gòu)函數(shù),釋放t1,這次就出現(xiàn)問(wèn)題了,因?yàn)槟菈K內(nèi)存已經(jīng)被釋放了,不能再次釋放。
默認(rèn)的淺拷貝其實(shí)就是下面的邏輯原理:

Teacher(const Teacher &obj) {
        this->name = obj.name;
        this->age = obj.age;
        cout << "拷貝構(gòu)造函數(shù)" << endl;
    }

深拷貝

解決淺拷貝問(wèn)題:

Teacher(const Teacher &obj) {
        this->name = (char*)malloc(100);
        strcpy(this->name, obj.name);
        this->age = age;
    }

當(dāng)Teacher t2 = t1時(shí),調(diào)用拷貝函數(shù),又在內(nèi)存中開(kāi)辟出一段內(nèi)存空間,然后指針指向這段內(nèi)存空間。
運(yùn)行打印結(jié)果為:

有參構(gòu)造函數(shù)
析構(gòu)函數(shù)
析構(gòu)函數(shù)

我們來(lái)簡(jiǎn)單分析一下運(yùn)行結(jié)果:Teacher t1("jonh", 23)會(huì)執(zhí)行有參構(gòu)造函數(shù),Teacher t2 = t1會(huì)調(diào)用拷貝構(gòu)造函數(shù),此時(shí)又在內(nèi)存中開(kāi)辟出一段內(nèi)存空間,然后t2name指針指向這段新開(kāi)辟出來(lái)的內(nèi)存空間,最后當(dāng)func函數(shù)執(zhí)行完之后,會(huì)首先釋放t2,調(diào)用析構(gòu)函數(shù),接下來(lái)釋放t1,由于之前t1t2指向的內(nèi)存空間不同,所以這時(shí)候釋放t1是沒(méi)有任何影響的,故而再次調(diào)用析構(gòu)函數(shù)。

總結(jié)

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

相關(guān)閱讀更多精彩內(nèi)容

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