C++-04、可變參數、static關鍵字、const修飾函數的this、實戰類寫法、友元

可變參數
#include <iostream>
#include <stdarg.h> // 可變參數的支持
using namespace std;

// Java的可變參數: int ...
// C++的可變參數寫法:...
// count的第一個用處:內部需要一個 存儲地址用的參考值,如果沒有這個參數,內部他無法處理存放參數信息
void sum(int count, ...) {
    va_list vp; // 可變參數的動作

    // 參數一:可變參數開始的動作vp
    // 參數二:內部需要一個 存儲地址用的參考值,如果沒有第二個參數,內部他無法處理存放參數信息
    va_start(vp, count);

    // 到這裏後:vp就已經有豐富的信息

    // 取出可變參數的一個值
    int number  = va_arg(vp, int);
    cout << number << endl;

    // 取出可變參數的一個值
    number  = va_arg(vp, int);
    cout << number << endl;

    // 取出可變參數的一個值
    number  = va_arg(vp, int);
    cout << number << endl;

    // 越界 系統值 亂碼
    // 取出可變參數的一個值 【取不到後,會取系統值 亂碼】
    number  = va_arg(vp, int);
    cout << number << endl;

    // 關閉階段
    va_end(vp);
}

// 1.可變參數
int main() {
    std::cout << "同學們大家好,我是Derry" << std::endl;

    sum(546, 6,7,8);

    return 0;
}
可變參數count變量的第二個用處
#include <iostream>
#include <stdarg.h> // 可變參數的支持
using namespace std;

// Java的可變參數: int ...
// C++的可變參數寫法:...

// count變量的第二個用處,用於循環遍歷長度
void sum(int count, ...) {
    va_list vp; // 可變參數的動作

    // 參數一:可變參數開始的動作vp
    // 參數二:內部需要一個 存儲地址用的參考值,如果沒有第二個參數,內部他無法處理存放參數信息
    va_start(vp, count);

    // 到這裏後:vp就已經有豐富的信息

    for (int i = 0; i < count; ++i) {
        int r = va_arg(vp, int);
        cout << r << endl;
    }

    // 關閉階段(規範:例如:file文件一樣 要關閉)
    va_end(vp);
}

// 1.可變參數
int main() {

    sum(3, 6,7,8); // 真實開發過程的寫法

    return 0;
}
static關鍵字==錯誤==示範
// 2.C++static關鍵字。 錯誤的寫法

#include <iostream>

using namespace std;

class Dog {
public:
    char * info;
    int age;

    // 已經編譯不成功,不允許這樣初始化
    // static int id = 9;
    static int id;

    Dog() {
        // 運行報錯
        // id = 9;
    }

    static void update() {
        // 運行報錯
        // id = 9;
    }

    void update2() {
        // 運行報錯
        // id = 9;
    }
};

int main() {
    Dog dog;
    Dog::update(); // 類名::可以調用靜態函數
    return 0;
}
static關鍵字==正確寫法==
// 2.C++static關鍵字。 正確的寫法

/**
 * 靜態的總結:
 * 1.可以直接通過類名::靜態成員(字段/函數)
 * 2.靜態的屬性必須要初始化,然後再實現(規則)
 * 3.靜態的函數只能取操作靜態的屬性和方法(Java)
 */

#include <iostream>

using namespace std;

class Dog {
public:
    char * info;
    int age;

    // 先聲明
    static int id;

    static void update() {
        id += 100;

        // 報錯:靜態函數不能調用非靜態函數(Java)
        // update2();
    }

    void update2() {
        id = 13;
    }
};

// 再實現
int Dog::id = 9;

int main() {
    Dog dog;
    dog.update2(); // 普通函數
    Dog::update(); // 靜態函數
    dog.update(); // 對象名.靜態函數(一般都是使用::調用靜態成員,這種方式可以 知道就行)

    cout << Dog::id << endl;
    return 0;
}

this
#include <iostream> // iostream.h 早期C++的方式

using namespace std;

class Student {
private:
    char *name;
    int age;

public:
    static int id; // 先聲明

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

public:
    // 默認的構造函數 棧區開闢空間 暴露 地址 == this指針 (和Java一致的思路)
};

// 再實現
int Student::id = 9527;

int main() {

    //四大區:棧區、堆區、全局區(靜態區、常量區、字符串區)、代碼區

    // ======= 常規使用下而已
    Student student;
    student.setAge(99);
    student.setName("Derry");
    cout << student.getName() << " , " << student.getAge()<< endl;

    // ==========  this 糾結   setAge在代碼區,有多個副本,對應不用指針
    Student student1;
    student1.setAge(88); // 設置值的時候,它怎麼知道是給student1的age設置值的?
    student1.id = 880;

    Student student2;
    student2.setAge(99); // 設置值的時候,它怎麼知道是給student2的age設置值的?
    student2.id = 990;

    Student::id = 666;

    // 它怎麼知道是獲取student1的age
    cout << " student1.getAge:" << student1.getAge() << endl;

    // 它怎麼知道是獲取student2的age
    cout << " student2.getAge:" << student2.getAge() << endl;

    cout << "student1.id:" << student1.id << endl;
    cout << "student2.id:" << student2.id << endl;
    cout << "Student:::" << Student::id << endl;


    return 0;
} // main函數彈棧會 隱式代碼:(棧區:delete student ..., 堆區需要自己手動delete)


const修飾函數的this意義何在
#include <iostream>

using namespace std;

// 如果是面試C++崗位,會被回到,不然問不到

class Worker {
public:
    char * name;
    int age = NULL; // C++中不像Java,Java有默認值, 如果你不給默認值,那麼就是系統值 -64664

    // int * const  指針常量 指針常量【地址對應的值能改,地址不可以修改】
    // const int *  常量指針 常量指針【地址可以修改,地址對應的值不能改】

    // 糾結:原理:爲什麼可以修改age
    // 默認持有隱式的this【類型 * const this】
    // 類型 * const 指針常量:代表指針地址不能被修改,但是指針地址的值是可以修改的
    void change1() {
        // 代表指針地址不能被修改
        // this = 0x6546;  // 編譯不通過,地址不能被修改,因爲是指針常量
        // 地址不可以修改
        // this = 0x43563;

        // 隱士的this
        // 但是指針地址的值是可以修改的
        // 地址對應的值能改
        this->age = 100;
        this->name = "JJJ";
    }

    // 默認現在:this 等價於 const Student * const  常量指針常量(地址不能改,地址對應的值不能改)
    void changeAction() const {
        // 地址不能改
        // this = 0x43563;

        // 地址對應的值不能改
        // this->age = 100;
    }

    // 原理:修改隱式代碼  const 類型 * const 常量指針常量
    void showInfo() const {
        // this->name = "";
        // this->age = 88;

        // 只讀的
        cout << "age:" << age << endl;
    }
};

int main() {
    return 0;
}

友元函數
// 老外:你是它的好朋友,那就可以拿私有成員給好朋友

#include <iostream>

using namespace std;

class Person {
private: // 私有的age,外界不能訪問
    int age = 0;

public:
    Person(int age) {
        this->age = age;
    }

    int getAge() {
        return this->age;
    }

    // 定義友元函數 (聲明,沒有實現)
    friend void updateAge(Person * person, int age);
};

// 友元函數的實現,可以訪問所以私有成員
void updateAge(Person* person, int age) {
    // 默認情況下:不能修改 私有的age
    // 誰有這個權限:友元(拿到所有私有成員)
    person->age = age;
}

int main() {
    Person person = Person(9);
    updateAge(&person, 88);

    cout << person.getAge() << endl;
    return 0;
}

實際寫法
  • Pig.h
#include <iostream>

using namespace std;

#ifndef PIG_H // 你有沒有這個宏(Java 宏==常量)
#define PIG_H // 定義這個宏

class Pig {
private:
    int age;
    char * name;

public:
    // 靜態成員聲明
    static int id;

    // 構造函數的聲明系列
    Pig();
    Pig(char *);
    Pig(char *,int);

    // 析構函數
    ~Pig();

    // 拷貝構造函數
    Pig(const Pig & pig);

    // 普通函數 set get
    int getAge();
    char * getName();
    void setAge(int);
    void setName(char *);

    void showPigInfo() const; // 常量指針常量 只讀

    // 靜態函數的聲明
    static void changeTag(int age);

    // 不要這樣幹
    // void changeTag(int age);

    // 友元函數的聲明
    friend void changeAge(Pig * pig, int age);
};

#endif // 關閉/結尾

  • Pig.cpp
#include "Pig.h"

// TODO  ======================  下面是 普普通通 常規操作 對象::

// 實現構造函數
Pig::Pig() {
    cout << "默認構造函數" << endl;
}

Pig::Pig(char * name) {
    cout << "1個參數構造函數" << endl;
}

Pig::Pig(char * name, int age) {
    cout << "2個參數構造函數" << endl;
}

// 實現析構函數
Pig::~Pig() {
    cout << "析構函數" << endl;
}

// 實現 拷貝構造函數
Pig::Pig(const Pig &pig) {
    cout << "拷貝構造函數" << endl;
}

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

void Pig::showPigInfo() const {

} // 常量指針常量 只讀



// TODO ===============================  靜態 和 友元 注意點 自己理解

// 實現 靜態屬性【不需要增加 static關鍵字】
int Pig::id = 878;

// 實現靜態函數,【不需要增加 static關鍵字】
void Pig::changeTag(int age) {

}

// 友元的實現
// 友元特殊:不需要關鍵字,也不需要 對象:: ,只需要保證 函數名(參數)
void changeAge(Pig * pig, int age) {

}
友元類
// 友元類 的 小故事 (ImageView 私有成員  可以通過Class來訪問,但是Class操作的native C++代碼)
// 下載 JDK native代碼 研究 【自己去研究】

// ImageView 私有成員  你能訪問它的私有成員嗎 Class
#include <iostream>

using namespace std;

class ImageView {
private:
    int viewSize;
    friend class Class; // 友元類
};

// Java每個類,都會有一個Class,此Class可以操作 ImageView私有成員(感覺很神奇)
class Class {
public:
    ImageView imageView;

    void changeViewSize(int size) {
        imageView.viewSize = size;
    }

    int getViewSize() {
        return imageView.viewSize;
    }
};

int main() {
    Class mImageViewClass;

    mImageViewClass.changeViewSize(600);

    cout << mImageViewClass.getViewSize() << endl;

    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章