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