当前位置: 首页 > wzjs >正文

dedecms 做的医院网站建筑学

dedecms 做的医院网站,建筑学,wordpress 建站教程 .pdf,网站界面设计修改要多少钱目录 基类与派生类之间的转换 派生类对象间的复制控制(重点) 基类与派生类之间的转换 一般情况下,基类对象占据的空间小于派生类对象。 (空继承时,有可能相等) 1:可否把一个基类对象赋值给一…

目录

基类与派生类之间的转换

派生类对象间的复制控制(重点)


基类与派生类之间的转换

一般情况下,基类对象占据的空间小于派生类对象。

(空继承时,有可能相等)

1:可否把一个基类对象赋值给一个派生类对象?可否把一个派生类对象赋值给一个基类对象?

2:可否将一个基类指针指向一个派生类对象?可否将一个派生类指针指向一个基类对象?

3:可否将一个基类引用绑定一个派生类对象?可否将一个派生类引用绑定一个基类对象?

Base base;
Derived d1;base = d1; //ok
d1 = base; //errorBase * pbase = &d1; //ok
Derived * pderived = &base //errorBase & rbase = d1; //ok
Derived & rderived = base; //error

以上三个ok的操作,叫做向上转型(往基类方向就是向上),向上转型是可行的

反之,基类向派生类转型称为向下转型,直接进行向下转型都会报错。

  • 用基类对象接受派生类对象的赋值(ok)

  • 用基类引用绑定派生类对象(ok)

  • 用基类指针指向派生类对象(ok)

—— 体现派生类向基类的转型。

向下转型有风险(如下)—— 以指针为例

Base类的指针指向Derived类的对象,d1对象中存在一个Base类的基类子对象,这个Base类指针所能操纵只有继承自Base类的部分;

Derived类的指针指向Base对象,除了操纵Base对象的空间,还需要操纵一片空间,只能是非法空间,所以会报错。其实可以理解为一个指针类型不同,所要管理的空间也不同。 还有可能是因为派生类都会包含有一个基类子对象,基类子对象放在内存的上面,指针可以指向类型相同的对象,所以基类可以指向派生类。派生类不可以指向基类Derived对象的内存结构为[Base::a][Derived::b]。基类指针指向派生类对象时,实际指向的是该对象中基类部分的起始地址,这种设计保证了基类指针能安全访问继承自基类的成员

补充:基类对象和派生类对象之间的转换没有太大的意义,基类指针指向派生类对象(基类引用绑定派生类对象)重点掌握,只能访问到基类的部分。

  • 有些场景下,向下转型是合理的,可以使用dynamic_cast来进行转换,如果属于合理情况,可以转换成功。

即基类向派生类的转型,我们看看这样的例子

Base base;
Derived d1;Base * pbase = &d1;
Derived * pderived = pbase;//这种转型是合理的,但是不能直接转型,会报错

注意:在使用dynamic_cast时还需要有多态的内容,我们需要加上一个虚函数。

class Base {
public:Base(long base): _base(base){ cout << "Base()" << endl; }virtual void display(){cout << "Base::display()" << endl;}~Base()
{ cout << "~Base()" << endl; 
}long _base = 10;
};class Derived
: public Base 
{
public:Derived(long base,long derived): Base(base), _derived(derived){ cout << "Derived(long)" << endl; 
}~Derived(){ cout << "~Derived()" << endl; 
}long _derived;
};
void test0(){	
Base base;
Derived d1;
Base * pbase = &d1;//此处的pbase本身就是指向派生类赌侠你给
//向下转型是合理的
//但是不能直接向下转型,直接向下转型会发生切片(就是派生类的部分被丢掉了)
//Derived *pderived = pbase;//如果不合理的向下转型,会返回一个空指针
//如果合理的向下转型,会返回一个合法的Derived *//向下转型
Derived * pd = dynamic_cast<Derived*>(pbase);
if(pd){
cout << "转换成功" << endl;
pd->display();
}else{
cout << "转换失败" << endl;
}
}

这里可以转换成功,因为pbase本身就是指向一个Derived对象

如下,属于不合理的转换,因为pbase本身是指向一个Base对象的,此时dynamic_cast会返回一个空指针。

void test1(){
Base base(1);
Derived d1(2,3);
Base * pbase = &base; Derived * pd = dynamic_cast<Derived*>(pbase);
if(pd){
cout << "转换成功" << endl;
pd->display();
}else{
cout << "转换失败" << endl;
}
}

—— 如上图,可以转换成功

结论:

可以用派生类对象赋值给基类对象(用基类对象接受派生类对象的赋值),可以用基类指针指向派生类对象,可以用基类引用绑定派生类对象。

反之则均不可。

派生类对象间的复制控制(重点)

复制控制函数就是 拷贝构造函数、赋值运算符函数

原则:基类部分与派生类部分要单独处理

(1)当派生类中没有显式定义复制控制函数时,就会自动完成基类部分的复制控制操作;

(2)当派生类中有显式定义复制控制函数时,不会再自动完成基类部分的复制控制操作,需要显式地调用;

对于拷贝构造,如果显式定义了派生类的拷贝构造,在其中不去显式调用基类的拷贝构造,那么无法通过复制初始化基类的部分,只能尝试用Base无参构造初始化基类的部分。如果Base没有无参构造,编译器就会报错。

对于赋值运算符函数,如果显式定义了派生类的赋值运算符函数,在其中不去显式调用基类的赋值运算符函数,那么基类的部分没有完成赋值操作。

如下,Derived对象没有指针成员申请堆空间,不需要显式定义拷贝构造函数和赋值运算符函数。编译器会自动完成基类部分的复制工作。

但是如果在Derived类中显式写出了复制控制的函数,就需要显式地调用基类的复制控制函数。

class Base{
public:Base(long base): _base(base){}protected:long _base = 10;
};class Derived
: public Base
{
public:Derived(long base, long derived): Base(base), _derived(derived){}Derived(const Derived & rhs): Base(rhs)//调用Base的拷贝构造, _derived(rhs._derived){cout << "Derived(const Derived & rhs)" << endl;}Derived &operator=(const Derived & rhs){//调用Base的赋值运算符函数Base::operator=(rhs);_derived = rhs._derived;cout << "Derived& operator=(const Derived &)" << endl;return *this;}private:long _derived = 12;
};

下面为测试代码可自行测试

#include <iostream>
using namespace std;class Base {
public:Base(long base): _base(base){//cout << "Base()" << endl;}Base(const Base& rhs):_base(rhs._base){cout << "Base()" << endl;}Base& operator=(const Base& rhs){cout << "Base的赋值运算符函数" << endl;_base = rhs._base;return *this;}void print()const {cout << "_base:" << _base << endl;}
protected:long _base;
};class Derived: public Base
{
public:Derived(long base, long derived): Base(base), _derived(derived){//cout << "Derived()" << endl;}void print()const {Base:: print();cout << "_derived:" << _derived << endl;}//显示的提供拷贝构造,要显示的调用基类的构造函数Derived(const Derived& rhs):Base(rhs)//显示调用基类的拷贝构造函数, _derived(rhs._derived){cout << "Derived()" << endl;}Derived& operator=(const Derived& rhs) {//要显示调用Base的赋值运算符函数Base::operator=(rhs);_derived = rhs._derived;cout << "Derived& operator=(const Derived &)" << endl;return *this;}private:long _derived;
};
void test()
{//Base base(10);//Derived d1(4, 6);//底层是base对象调用Base类的赋值运算符函数//base.operator=(d1);//形参 const Base & rhs  实参 d1//base = d1;//cout << base._base << endl;
}
void test1()
{Derived d1(6, 9);d1.print();Derived d2(5, 7);d1 = d2;d1.print();Derived d3 = d2;d3.print();
}
int main()
{test1();return 0;
}#include <iostream>
using namespace std;class Base {
public:Base(long base): _base(base){//cout << "Base()" << endl;}Base(const Base& rhs):_base(rhs._base){cout << "Base()" << endl;}Base& operator=(const Base& rhs){cout << "Base的赋值运算符函数" << endl;_base = rhs._base;return *this;}void print()const {cout << "_base:" << _base << endl;}
protected:long _base;
};class Derived: public Base
{
public:Derived(long base, long derived): Base(base), _derived(derived){//cout << "Derived()" << endl;}void print()const {Base:: print();cout << "_derived:" << _derived << endl;}//显示的提供拷贝构造,要显示的调用基类的构造函数Derived(const Derived& rhs):Base(rhs)//显示调用基类的拷贝构造函数, _derived(rhs._derived){cout << "Derived()" << endl;}Derived& operator=(const Derived& rhs) {//要显示调用Base的赋值运算符函数Base::operator=(rhs);_derived = rhs._derived;cout << "Derived& operator=(const Derived &)" << endl;return *this;}private:long _derived;
};
void test()
{//Base base(10);//Derived d1(4, 6);//底层是base对象调用Base类的赋值运算符函数//base.operator=(d1);//形参 const Base & rhs  实参 d1//base = d1;//cout << base._base << endl;
}
void test1()
{Derived d1(6, 9);d1.print();Derived d2(5, 7);d1 = d2;d1.print();Derived d3 = d2;d3.print();
}
int main()
{test1();return 0;
}

如果Derived类的数据成员申请了堆空间,那么必须手动写出Derived类的复制控制函数,此时就要考虑到基类的复制控制函数的显式调用。

(如果只是Base类的数据成员申请了堆空间,那么Base类的复制控制函数必须显式定义,Derived类自身的数据成员如果没有申请堆空间,不用显式定义复制控制函数)

练习:将Base类的数据成员换成char *类型,体验一下派生类的复制。

如果派生类中没有指针数据成员,不需要显式写出复制控制函数。编译器会自动进行基类部分的复制控制。

  • 对于派生类的拷贝构造函数

如果给Derived类中添加一个char * 成员,依然不显式定义Derived的复制控制函数。

那么进行派生类对象的复制时,基类的部分会完成正确的复制,派生类的部分只能完成浅拷贝(最终对象销毁时导致double free问题)

Derived d1("hello","world");
Derived d2 = d1;

如果接下来给Derived类显式定义了拷贝构造,但是没有在这个拷贝构造中显式调用基类的拷贝构造(没有写任何的基类子对象的创建语句),会直接报错。

(—— 在派生类的构造函数的初始化列表中没有显式调用基类的任何的构造函数,编译器会自动调用基类的无参构造,此时基类没有无参构造,所以报错)

因为没有初始化d2的基类子对象,需要在derived的拷贝构造函数中显式调用Base的拷贝构造。

  • 对于赋值运算符函数

如果接下来给Derived显式定义赋值运算符函数,但是没有在其中显式调用基类的赋值运算符函数

Derived d1("hello","world");
Derived d2 = d1;
Derived d3("beijing","shanghai");d2 = d3;  //派生类对象的部分完成了复制,但是基类部分没有完成复制

基类的部分不会自动完成复制,需要在Derived的赋值运算符函数中显式调用Base的赋值运算符函数,才能完成正确的复制

总结:

给Derived类手动定义复制控制函数,注意在其中显式调用相应的基类的复制控制函数

(注意:派生类对象进行复制时一定会马上调用派生类的复制控制函数,在进行复制时会首先复制基类的部分,此时调用基类的复制控制函数)

Derived(const Derived & rhs): Base(rhs)//显式调用基类的拷贝构造, _pderived(new char[strlen(rhs._pderived) + 1]()){strcpy(_pderived, rhs._pderived);cout << "Derived(const Derived &)" << endl;}Derived & operator=(const Derived & rhs){cout << "Derived & operator=(const Derived &)" << endl;if(this != &rhs){//显式调用基类的赋值运算符函数Base::operator=(rhs);//关键delete [] _pderived;_pderived = new char[strlen(rhs._pderived) + 1]();strcpy(_pderived,rhs._pderived);_derived = rhs._derived;}return *this;
}

下面为测试代码可自行测试

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;class Base {
public:Base(long base, const char* pbase): _base(base),_pbase(new char [strlen(pbase)+1]()){strcpy(_pbase, pbase);cout << "Base()" << endl;}Base(const Base& rhs):_base(rhs._base),_pbase(new char [strlen(rhs._pbase)+1]()){strcpy(_pbase, rhs._pbase);cout << "Base()" << endl;}Base& operator=(const Base& rhs){if (this != &rhs){delete[] _pbase;_pbase = new char[strlen(rhs._pbase) + 1]();strcpy(_pbase, rhs._pbase);_base = rhs._base;}cout << "Base的赋值运算符函数" << endl;return *this;}void print()const {cout << "_pbase:" << _pbase << endl;cout << "_base:" << _base << endl;}
protected:long _base;char* _pbase;
};class Derived: public Base
{
public:Derived(long base, const char* pbase,long derived, const char * pderived): Base(base, pbase), _derived(derived), _pderived(new char [strlen(pderived) + 1] ()){strcpy(_pderived, pderived);cout << "Derived()" << endl;}void print()const {Base::print();cout << "_derived:" << _derived << endl;cout << "_pderived:" << _pderived << endl;}//显示的提供拷贝构造,要显示的调用基类的构造函数Derived(const Derived& rhs):Base(rhs)//显示调用基类的拷贝构造函数, _derived(rhs._derived), _pderived(new char [strlen(rhs._pderived)+1]()){strcpy(_pderived, rhs._pderived);cout << "Derived()" << endl;}Derived& operator=(const Derived& rhs) {if (this != &rhs){Base::operator=(rhs);delete[] _pderived;//要显示调用Base的赋值运算符函数_derived = rhs._derived;_pderived = new char[strlen(rhs._pderived) + 1]();strcpy(_pderived, rhs._pderived);}cout << "Derived& operator=(const Derived &)" << endl;return *this;}~Derived(){if (_pderived){delete[] _pderived;_pderived = nullptr;}}
private:long _derived;char* _pderived;
};
void test()
{//Base base(10);//Derived d1(4, 6);//底层是base对象调用Base类的赋值运算符函数//base.operator=(d1);//形参 const Base & rhs  实参 d1//base = d1;//cout << base._base << endl;
}
void test1()
{Derived d1(6,"hello", 9,"beijing");d1.print();Derived d2(5, "world", 7, "hhhh");d1 = d2;d1.print();Derived d3 = d2;d3.print();
}
int main()
{test1();return 0;
}

http://www.dtcms.com/wzjs/796751.html

相关文章:

  • 北京住房和城乡建设部网站官网dede 网站地图模版
  • 沧州网站建设专业定制搜索排名的影响因素
  • 烟台网站制作山海云网站设计思路文案范文
  • 官方网站建设哪家公司好教育行业网站制作
  • WordPress在线留言插件手机优化设置
  • 网站制作公司怎么看联合外发加工网
  • 用万网建设网站教程视频陕西做网站的公司
  • 网站建设协议一百互联可以自己设计图案的软件
  • 苏州市住房和城乡建设部网站无极网站建设
  • 移动端公众号网站开发东莞知名企业
  • 如何做cpa单页网站自己制作简单的小程序
  • 合肥企业网站制作多多短视频下载赚钱
  • 专门做t恤的网站上海网站的优化
  • 网站色彩学牡丹江省
  • 网站制作的分割线怎么做什么网站可以帮人做ppt赚钱
  • 南京 高端网站建设基本网站建设
  • 做网站免费服务器哪家好反恶意镜像网站
  • 网站建设综合训练的实验目的百度 移动网站优化
  • 上海网站建设培训学校大良网站制作
  • golang 网站开发 开源设计网站用什么语言
  • 网站建设时 网站信息可以边建设边组织响应式网站的优缺点
  • 新手做网站盈利seo快速推广窍门大公开
  • 网站的绝对路径公司部门撤销要求转岗不同意怎么办
  • 免费网站空间哪个好中山网站制作定制
  • 建网站衡水哪家强?长沙企业推广
  • 泰州网站建设哪家好北京专业的做网站
  • 网站建设联系方式免费企业网站模板psd
  • 平台网站怎么推广wordpress教程php二次开发
  • 北京的制作网站的公司有哪些网站制作实训
  • 百度上找不到网站深圳网站搜索引擎优化