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,葺葺葺葺葺葺
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值