4.5 基类与派生类对象之间的赋值兼容关系
在一定条件下,不同类型的数据之间可以进行类型转换,例如可以将整型数据赋给双精度型变量。
在赋值之前,先把整型数据转换为双精度型数据,然后再把它双精度型变量。这种不同类型之间的自动转换,称为赋值兼容。在基类和派生类对象之间也存在有赋值兼容关系,基类和派生类对象之间的赋值兼容规则是指在需要基类对象的任何地方,都可以使用公有派生类的对象来代替。因为,通过公有继承,除了构造函数和析构函数外,派生类保留了基类其他的所有的成员。那么,派生类就具有基类的全部功能,凡是基类能够实现的功能,公有派生类都能实现。我们可以将派生类对象的值赋给基类对象,在用到基类对象的时候可以用其子类对象代替。

例如,下面声明的两个类:

class Base{          //声明基类
...
};
class Derived:public Base{ //声明基类Base的公有派生类Derived
...
};

根据兼容规则,在基类Base的对象可以使用的任何地方,都可以用派生类Derived的对象来代替,
但只能使用从基类继承来的成员。具体表现在以下几个方面:

(1)派生类对象可以向基类对象赋值,即用派生类对象中从基类继承来的数据成员,逐个赋值给基类对象的数据成员。

例如:

Base b; //定义基类Base的对象b
Derived d;  //定义基类Base的公有派生类Derived的对象d
b=d;           //用派生类Derived的对象d对基类Base的对象b进行赋值

这样的赋值效果是:对象b中所有数据成员都将具有对象d中对应数据成员的值。

(2)派生类对象可以初始化基类对象的引用。例如:
Base b; //定义基类Base的对象b
Derived d; //定义基类Base的公有派生类Derived的对象d
Base &br=d; //定义基类Base的对象的引用br,并用派生类Derived的对象对其进行初始化

(3)派生类对象地址可以赋值给指向基类对象的指针。例如:
Derived d; //定义基类Base的公有派生类Derived的对象b
Base *bp=&d; //把派生类对象的地址&d赋值给指向基类的指针bp,也就是说使指向基类
                         //对象的指针bp也可以指向派生类对象d

(4)如果函数的形参是基类对象或基类对象的引用,在调用函数时可以将派生类对象作为实参。例如:
class Base{ //声明基类Base
       public:
               int i;
               ...
};
class Derived:public Base{ //声明Base的公有派生类Derived
              ...
};
void fun(Base &bb)
{
              cout<<bb.i<<endl; //输出该引用所代表的对象的数据成员i
}

在调用函数fun时,可以用派生类Derived的对象d4作为实参:
fun(d4);
输出派生类Derived的对象d4赋值给基类数据成员i的值。

//基类与派生类对象之间的交换

#include<iostream>
using namespace std;
class Base{ //声明基类Base
public:
int i;
Base(int x) //基类Base的构造函数
{
i = x;
}
Base(const Base &b)
{
cout<<"Base Copyconstructor"<<endl;
}
void show() //成员函数
{
cout<<"i="<<i<<endl;
}
};
class Derived:public Base{ //声明基类Base的公有派生类Derived
public:
Derived(int x):Base(x) //派生类的构造函数
{}
Derived(const Derived &d):Base(d)
{
cout<<"Derived Copyconstructor"<<endl;
}
};
void fun(Base &bb) //普通函数,形参为基类对象的引用
{
cout<<bb.i<<endl;
}
int main()
{
Base b1(); //定义基类对象b1
b1.show();
Derived d1(); //定义派生类对象d1
b1=d1; //用派生类对象d1给基类对象b1赋值
b1.show(); Derived d2(); //定义派生类对象d2
Base &b2=d2; //用派生类对象d2来对基类对象的引用b2进行初始化
b2.show(); Derived d3(); //定义派生类对象d3
Base *b3=&d3; //把派生类对象的地址&d3赋值给指向基类对象的指针b3
b3->show(); Derived d4(); //定义派生类对象d4
fun(d4); //派生类对象d4作为函数fun的实参 Derived d6(d4);
return ;
} /*
程序运行结果如下:
Base 100
Base 11
Base 22
Base 33
44
Base Copyconstructor
Derived Copyconstructor

说明:

(1)声明为指向基类对象的指针可以指向它的公有派生类的对象,但不允许指向它的私有派生的对象。
例如:
class Base{
...
};
class Derived:private Base{
...
};
int main()
{
Base op1,*ptr; //定义基类Base的对象op1及其指向基类Base的指针ptr
Derived op2; //定义派生类Derived的对象op2
ptr = &op1; //将指针ptr指向基类Base对象op1
ptr = &op2; //错误,不允许将指向基类Base的指针ptr指向它的私有派生类对象op2
......
return ;
} (2)允许将一个声明为指向基类的指针指向其公有派生类的对象,但是不能将一个声明为指向派生类
对象的指针指向其基类的一个对象。
例如:
class Base{
...
};
class Derived:public Base{
...
};
int main()
{
Base obj1; //定义基类Base的对象obj1
Derived obj2,*ptr; //定义派生类Derived的对象obj2及其指向派生类对象的指针ptr
ptr = &obj2; //将指针ptr指向派生类Derived对象obj2
ptr = &op2; //错误,不允许将指向派生类Derived指针ptr指向它的基类Base对象obj1
......
return ;
}

C++:基类与派生类对象之间的赋值兼容关系的更多相关文章

  1. 详解C++中基类与派生类的转换以及虚基类

    很详细!转载链接 C++基类与派生类的转换在公用继承.私有继承和保护继承中,只有公用继承能较好地保留基类的特征,它保留了除构造函数和析构函数以外的基类所有成员,基类的公用或保护成员的访问权限在派生类中 ...

  2. (转) C++中基类和派生类之间的同名函数的重载问题

    下面有关派生类与基类中存在同名函数 fn: class A { public: void fn() {} void fn(int a) {} }; class B : public A { publi ...

  3. C++基类和派生类之间的转换

    本文讲解内容的前提是派生类继承基类的方式是公有继承,关键字public 以下程序为讲解用例. #include<iostream> using namespace std; class A ...

  4. c++,派生类对象可以对基类赋值,基类对派生类不可以赋值

    派生类对象可以对基类对象赋值,赋值时属于派生类独有的部分就舍弃不用. #include <iostream> using namespace std; class DemoA { publ ...

  5. C++学习21 基类和派生类的赋值

    在C/C++中,经常会发生数据类型转换,例如整型数据可以赋值给浮点型变量,在赋值之前,先把整型数据转换为浮点型:反过来,浮点型数据也可以赋值给整型变量. 数据类型转换的前提是,编译器知道如何对数据进行 ...

  6. OOP1(定义基类和派生类)

    面向对象程序设计基于三个基本概念:数据抽象,继承和动态绑定 数据抽象是一种依赖于接口和实现分离的编程技术.继承和动态绑定对程序的编号有两方面的影响:一是我们可以更容易地定义与其它类相似但不完全相同的类 ...

  7. 不可或缺 Windows Native (21) - C++: 继承, 组合, 派生类的构造函数和析构函数, 基类与派生类的转换, 子对象的实例化, 基类成员的隐藏(派生类成员覆盖基类成员)

    [源码下载] 不可或缺 Windows Native (21) - C++: 继承, 组合, 派生类的构造函数和析构函数, 基类与派生类的转换, 子对象的实例化, 基类成员的隐藏(派生类成员覆盖基类成 ...

  8. c++中基类与派生类中隐含的this指针的分析

    先不要看结果,看一下你是否真正了解了this指针? #include<iostream> using namespace std; class Parent{ public: int x; ...

  9. 基类和派生类--this

    基类指针在程序运行的时候的确指向的是一个派生类的对象,但指针的类型仍然是基类指针.C++是一种强类型语言,因此不能用基类指针类型的指针直接调用派生类:而且,同一个类可能有多种不同的派生类,因此不知道实 ...

随机推荐

  1. Android中解析JSON形式的数据

    1.JSON(JavaScript Object Notation) 定义: 一种轻量级的数据交换格式,具有良好的可读和便于快速编写的特性.业内主流技术为其提供了完整的解决方案(有点类似于正则表达式, ...

  2. 给同一个表中的两个外键写sql

    一个表有两个外键都指向另一个表的主键时,如何检索他们的数据? 例如,表TableA有两个列,puserID和friendID. 表TableB有两个列,userID和userName. 我们怎样检索数 ...

  3. Mysql几种索引类型的区别及适用情况

    如大家所知道的,Mysql目前主要有以下几种索引类型:FULLTEXT,HASH,BTREE,RTREE. 那么,这几种索引有什么功能和性能上的不同呢? FULLTEXT 即为全文索引,目前只有MyI ...

  4. SHELL syntax error:unexpected end of file 提示错误

    SHELL syntax error:unexpected end of file 提示错误 if [ -n "$1" ] then " else " fi e ...

  5. ZedGrap控件绘制图表曲线

    问题描述: 使用C#中ZedGrap控件绘制图表曲线图 ZedGrap 介绍说明:     安装ZedGrap控件 ZedGraph控件dll文件: 添加ZedGraph控件,首先在新建立的C#图像工 ...

  6. 剑指offer--面试题13

    题目:以O(1)的时间复杂度删除单链表中的某个节点 自己所写代码如下: //以O(1)时间删除链表节点 //要求:单向链表,头指针,待删节点指针 //链表节点 struct ListNode { in ...

  7. 剑指offer--面试题5

    到现在为止,看过的书+代码有一定量了,并且也参加了个比赛,给自己的总体感觉:编程需要的是灵活的头脑,书里的东西只是讲个规则.思想,其实际实现可以千差万别!   潜在的规则+灵活的思维 = 程序! 在做 ...

  8. intellij idea 14 ULTIMATE 注册码

    Name:happy KEY:63763-YCO0I-QR4TV-G4I3E-4XGK9-GQSQ3

  9. [设计模式] 17 中介者模式 Mediator Pattern

    在GOF的<设计模式:可复用面向对象软件的基础>一书中对中介者模式是这样说的:用一个中介对象来封装一系列的对象交互.中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变 ...

  10. uva 10160

    一开始写的代码加上各种剪枝后还是超时, 然后看了一下状态压缩后过了,两个代码的具体思想是一样的,状态压缩后可以大大提升性能 #include <cstdio> #include <c ...