C++ 繼承與派生 派生類與基類之間的轉換關係,函數運算符調用關係

C++ 繼承與派生 派生類與基類之間的轉換關係,函數運算符調用關係


一.派生類轉換爲基類

總結:在轉換的過程中,基類總是在左邊,派生類總是在右邊,相當於是一次向上轉型
有三種轉換形式:

  • 基類指針指向new出的派生類
  • 基類引用派生類
  • 基類對象 = 派生類對象 ,利用賦值運算符

用程序來理解:

#include <iostream>
using std::cout;
using std::endl;

//基類與派生類之間的相互轉換
/*
總結:在轉換的過程中,基類總是在左邊,派生類總是在右邊,相當於是一次向上轉型
*/


class Point
{
public:
    explicit Point(int x, int y) : _x(x), _y(y)
    {
    }

    void print() const
    {
        cout << "(" << _x << "," << _y << ")" << endl;
    }

    int getX() const { return _x; }
    int getY() const { return _y; }

private:
    int _x;
    int _y;
};

class Point3D : public Point
{
public:
    Point3D(int x, int y, int z) : Point(x, y), _z(z)
    {
    }

    void print() const
    {
        cout << "(" << getX() << "," << getY() << "," << _z << ")" << endl;
    }

private:
    int _z;
};

//1.派生類對象賦值給基類對象
void test1()
{
    Point p1(1, 2);
    Point3D p2(3, 4, 5);
    p1.print();
    p2.print();

    p1 = p2; //派生類對象可以向基類對象賦值
    //p2 = p1;//反之不行
    p1.print();
}

//2.派生類對象賦值給基類的引用
void test2()
{
    Point3D p2(3, 4, 5);
    p2.print();

    Point &p1 = p2;
    p1.print();    

}

//3.基類指針指向派生類對象
void test3(){
    Point3D p1(1,2,3);

    Point *p2 = &p1;
    p2->print();
}

int main()
{
    // test3();
    return 0;
}

二.派生類與基類:調用函數與運算符

派生類的
1.構造函數執行過程
2.拷貝構造函數執行過程
3.=運算符執行過程
4.<< 運算符執行過程

首先來看這個主程序:


class Base
{
public:
    Base(const char *str)
        : _pstr(new char[strlen(str) + 1])
    {
        strcpy(_pstr, str);
        cout << "Base(const char* str)" << endl;
    }

    Base(const Base &lhs)
        : _pstr(new char[strlen(lhs._pstr) + 1])
    {
        strcpy(_pstr, lhs._pstr);
        cout << "Base(const Base& lhs)" << endl;
    }

    Base &operator=(const Base &lhs)
    {
        if (this != &lhs)
        {
            delete[] _pstr;
            _pstr = new char[strlen(lhs._pstr) + 1];
            strcpy(_pstr, lhs._pstr);
            cout << "Base& operator=(const Base&)" << endl;
        }
        return *this;
    }

    ~Base()
    {
        if (_pstr)
        {
            cout << "~Base()" << endl;
            delete[] _pstr;
            _pstr = NULL;
        }
    }

    friend ostream &operator<<(ostream &, const Base &);

private:
    char *_pstr;
};

ostream &operator<<(ostream &os, const Base &lhs)
{
    os << lhs._pstr;
    return os;
}

class Derived : public Base
{
public:
    Derived(const char *str1, const char *str2)
        : Base(str1), _pstr(new char[strlen(str2) + 1])
    {
        strcpy(_pstr, str2);
        cout << "Derived(const char*, const char*)" << endl;
    }

    Derived(const char *str)
        : _pstr(new char[strlen(str) + 1]), Base(str)
    {
        strcpy(_pstr, str);
        cout << "Derived(const char* str)" << endl;
    }

    Derived(const Derived &lhs)
        : _pstr(new char[strlen(lhs._pstr) + 1]), Base(lhs) //這裏的Derived類型會自動轉換爲Base類型,再調用Base的拷貝構造函數
    {
        strcpy(_pstr, lhs._pstr);
        cout << "Derived(const Derived& lhs)" << endl;
    }

    Derived &operator=(const Derived &lhs)
    {
        if (this != &lhs)
        {
            delete[] _pstr;
            _pstr = new char[strlen(lhs._pstr) + 1];
            strcpy(_pstr, lhs._pstr);

            #if 0
            Base& b = static_cast<Base&>(*this);
            b = static_cast<Base>(lhs);
            #endif 
            Base::operator=(lhs);

            cout << "Derived& operator=(const Derived&)" << endl;
        }
        return *this;
    }

    ~Derived()
    {
        if (_pstr)
        {
            cout << "~Derived()" << endl;
            delete[] _pstr;
        }
    }

    friend ostream &operator<<(ostream &, const Derived &);

private:
    char *_pstr;
};

ostream &operator<<(ostream &os, const Derived &lhs)
{
    const Base &b = static_cast<const Base &>(lhs);
    os << b << "," << lhs._pstr;
    return os;
}

接下來是測試程序

1.基類(派生類) 調用拷貝構造函數:

在執行Base b(d)的過程中:
d傳入參數中,強制轉換爲Base類,在調用Base類的拷貝構造函數

注意:派生類(基類) 這樣調用拷貝構造函數是非法的,除非重定義

void test0(){
    Derived d("Base", "Derived");
    Base b(d);
    cout << b << endl;
    cout << d << endl;

}

2.基類 = 派生類 調用=運算符

在執行強制類型轉換的時候:
1).首先調用Base類的拷貝構造函數,將d強制轉換後成Base類之後進行拷貝構造;
2).在用Base類中的賦值運算符,將其賦值給b
3).臨時拷貝構造的類進行析構

注意:
1).如果不使用static_cast的話則不會調用拷貝構造函數,但是並不安全!
2).派生類 = 基類 這樣轉換是非法的,除非重定義!


void test1()
{
    Base b("Base");
    Derived d("Derived_base1", "derived");
    b = static_cast<Base>(d);
    cout << b << endl;
}

3.派生類 = 派生類 :

需要在派生類中重載運算符 =
注意:如果不在Derived類中重載=運算符的話,編譯器只會自動調用Base類的=運算符,但是Derived類中的函數則是會讓_pstr改變指向而已,並不會新開闢空間,從而產生錯誤!(類似於淺拷貝)


void test2(){
    Derived *d1 = new Derived("base1", "derived1");
	Derived *d2 = new Derived("base2", "derived2");
	*d2 = *d1;
	delete d1;
	d1 = NULL;
	//不在Derived中重載=的話
	cout << *d2 << endl;//base1,葺葺葺葺葺葺
}

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