1. 程式人生 > >c++操作符過載多檔案形式練習

c++操作符過載多檔案形式練習

Array.h

#pragma once
//標頭檔案中宣告的函式,編譯器會自動去各.cpp檔案去匹配物件的具體定義
//標頭檔案中不能包含.cpp檔案,編譯時候會報錯誤,但可以包含其他的.h標頭檔案
//標頭檔案中不能定義函式的具體內容,只可以宣告函式,但可以定義型別,如果型別裡包含函式,就可以直接定義了,也可以先在類宣告,在其他.cpp檔案中定義,編譯器會自動匹配,在其他.cpp檔案中定義時,不僅要包含標頭檔案,還需要帶上作用域
//當你的標頭檔案中呼叫了別的檔案的型別時,一定需要宣告,不然會報錯誤,或者包含別的帶有這個陌生型別宣告的標頭檔案
#include <iostream>

using namespace std;//型別ostream包含在標頭檔案<iostream>中的std作用域中,因此如果類裡宣告有陌生型別時,我們需要宣告,不然編譯器不知道這個型別是什麼

//函式宣告,實現不可以在標頭檔案中寫出
void print1();
void print2();
//友元函式的宣告,具體定義編譯器會從.cpp檔案中幫我們自動匹配


struct test
{
    int a;
    int b;
    void print3()
    {
        cout << "3333333333333333333333" << endl;
    }
};

class Array
{
public:
    //友元函式在類裡僅僅是指定訪問許可權的宣告,並非傳統意義上的函式宣告,雖然有的編譯器允許在未宣告的情況下允許呼叫,但最好還是寫出宣告
    friend ostream &operator<<(ostream &os, const Array &a);
    friend void function(Array &a);
    friend test setData(Array &a, test &t);
    friend istream &operator>>(istream &in, Array &a);
    Array();
    Array(int len);
    Array(const Array &another);
    void setData(int index, int data);
    int getData(int index);
    int getLen()const;
    ~Array();
    int &operator[](int i)const;
    bool operator==(Array &another);
    bool operator!=(Array &another);
    Array &operator=(Array &another);
private:
    int len;
    int *p;
};

//友元函式宣告
test setData(Array &a, test &t);
void function(Array &a);
ostream &operator<<(ostream &os, const Array &a);
istream &operator>>(istream &in, Array &a);

Array.cpp

#include "Array.h"

Array::Array()
{
    int len = 0;
    this->p = NULL;
}
Array::Array(int len)
{
    if (len <= 0)
    {
        cout << "error" << endl;
        return;
    }
    this->len = len;
    p = new int[len];
}
//這就是深拷貝,和解構函式一起出現,成對出現,有指標開闢另外一處空間,就需要解構函式去處理那塊空間,也就需要深拷貝函式進行初始化拷貝構造
Array::Array(const Array &another)
{
    len = another.len;
    p = new int[len];
    for (int i = 0; i < len; i++)
    {
        p[i] = another.p[i];//並把開闢空間的資料拷貝給p指向的空間
    }
    cout << "array copy" << endl;
}
void Array::setData(int index, int data)
{
    if (index<0 || index>len - 1)
    {
        cout << "error" << endl;
    }
    p[index] = data;
}
int Array::getData(int index)
{
    if (index<0 || index>len - 1)
    {
        cout << "error" << endl;
    }
    return p[index];
}
test setData(Array &a, test &t)
{
    t.a = a.len;
    t.b = a.len;
    return t;
}
int Array::getLen()const
{
    return this->len;
}
Array::~Array()
{
    cout << "~array()" << endl;
    delete[] p;
}
void print1()
{
    cout << "11111111111111111111" << endl;
}
void print2()
{
    cout << "222222222222222222222222222" << endl;
}
void function(Array &a)
{
    cout << a.p[0] << endl;
}
int &Array::operator[](int i)const//這只是表面在這個函式的範圍內,物件是不可修改的,當執行完這個函式時,const修飾的效果就不在了
{
    return p[i];
}
//使用const修飾物件的時候,就不可以再使用友元函式直接呼叫物件的私有成員變數,因為你呼叫私有成員變數就可以改變它的值了,但物件是被cosnt修飾過的,裡面的成員不可改變
//這時候可以使用類內部的方法來獲得類內部私有成員變數的值,但一定不能在const修飾物件的時候使用友元函式直接呼叫類裡的私有成員變數,是錯誤的
//當使用例:getLen()方法時,此方法隱式的傳入了物件a,即等價於getLen(&a),此時物件是可以修改的,而上級裡我們要求的是物件不可以修改,因此需要在getLen()方法後加const,即getLen()const;
//也就是當這個總函式裡確定物件為const修飾不可改變時,這個函式裡呼叫的任何小函式用到這個物件的也不可以改變,只有當大函式生命週期結束時,修飾效果才結束
ostream &operator<<(ostream &os, const Array &a)
{
    for (int i = 0; i < a.getLen(); i++)
    {
        //在這個函式的作用域裡,os即為cout,因此用os代替cout
        os << "a[" << i << "]=" << a[i] << endl;
    }
    return os;
}
//輸入便需要改變物件,因此一定不要加const修飾
istream &operator>>(istream &in, Array &a)
{
    cout << "please input value" << endl;
    for (int i = 0; i < a.len; i++)
    {
        cout << "a[" << i << "]=";
        in >> a.p[i];
    }
    return in;
}
bool Array::operator==(Array &another)
{
    for (int i = 0; i < len; i++)
    {
        if (p[i] != another.p[i])
        {
            return false;
        }
    }
    return true;
}
bool Array::operator!=(Array &another)
{
    int key = 0;
    for (int i = 0; i < len; i++)
    {
        if (p[i] != another.p[i])
        {
            return true;
        }
    }
    return false;
}
Array &Array::operator=(Array &another)
{
    if (this == &another)
    {
        return *this;
    }
    if (this->p != NULL)
    {
        delete[] this->p;
    }
    this->len = another.len;
    this->p = new int[this->len];
    for (int i = 0; i < len; i++)
    {
        this->p[i] = another.p[i];
    }
    another[1] = 10;//當操作符過載過以後即可以呼叫,在類裡的方法也可以直接呼叫
    return *this;

}

main.cpp

#define _CRT_SECURE_NO_WARNINGS

#include "Array.h"

int main()
{
    Array a1(10);
    int i = 0;
    for (i = 0; i < 10; i++)
    {
        a1.setData(i, 100 - i);
    }
    Array a2(a1);
    /*
    //下面的三段程式碼是錯誤的,因為不是呼叫拷貝建構函式,物件a3裡的值與a1完全相同,即a3裡的指標與a1裡的指標指向同一片區域,因此析構時同一塊區域被析構了兩次,所以不可以
    //當有深拷貝的時候,不可以直接為物件賦值,除非重寫運算子
    Array a3;
    a3 = a1;
    cout << "a3.p[0]=" << a3.getData(0) << endl;
    */

    a1[0] = 1000;
    
    cout << a1;
    function(a1);

    test t;
    t = setData(a1, t);

    print1();
    print2();

    //cin >> a1;
    //cout << a1;

    if (a1 == a2)
    {
        cout << "================" << endl;
    }
    if (a1 != a2)
    {
        cout << "'\\\\\\\\\\\\\\\\\\\\\\'" << endl;
    }

    a1 = a2;

    return 0;
}