赋值兼容规则(C++)

在一定条件下,不同类型的数据之间可以进行类型转换,如可以将整型数据赋给双精度型变量。在赋值之前,先把整型数据转换成双精度型数据,然后再把它赋给双精度型变量。这种不同类型数据之间的自动转换和赋值,称为赋值兼容。在基类和派生类对象之间也存有赋值兼容关系,基类和派生类对象之间的赋值兼容规则是指在需要基类对象的任何地方,都可以使用其子类对象来代替。

下面主要讲积基类和派生类对象之间的赋值兼容
派生类的对象可以赋值给基类对象。

? ?A a1; //定义基类A对象a1
? ?B b1; //定义类A的公用派生类B的对象b1
? ?a1=b1; //用派生类B对象b1对基类对象a1赋值

??在赋值时舍弃派生类自己的成员,只进行数据成员的赋值。

? 实际上,所谓赋值只是对数据成员赋值,对成员函数不存在赋值问题,内存中数据成员和成员函数是分开的。

?注意: 赋值后不能企图通过对象a1去访问派生类对象b1的成员,因为b1的成员与a1的成员是不同的。??

假设age是派生类B中增加的公用数据成员,分析下面的用法:

? a1.age=23;//错误,a1中不包含派生类中增加的成员
b1.age=21; //正确,b1中包含派生类中增加的成员

只能用子类对象对其基类对象赋值,而不能用基类对象对其子类对象赋值,理由是显然的,两种对象的大小是不同的,因为基类对象不包含派生类的成员无法对派生类的成员赋值。同理,同一基类的不同派生类对象之间也不能赋值

2·派生类的对象可以初始化基类的引用。
已定义了基类A对象a1,可以定义a1的引用变量:

? ? A a1; //定义基类A对象a1
? ? B b1; //定义公用派生类B对象b1
? ? A &r=a1; //定义基类A对象的引用变量r(A的别名是r),并用a1对其初始化

这时,r和a1共享同一段存储单元。也可以用派生类对象初始化引用变量r,将上面最后一行改为

A& r=b1;//定义基类A对象的引用变量r,并用派生类B对象b1//对其初始化

注意: 此时r并不是b1的别名,也不与b1共享同一段存储单元。它只是b1中基类部分的别名

这里的r定义为A类的引用,所以它的有效范围就只有A类那么大,r与b1中基类部分共享同一段存储单元,r与b1具有相同的起始地址。?
如果函数的参数是基类对象或基类对象的引用,相应的实参可以用子类对象。
3·派生类对象的地址可以赋给指向基类的指针。也就是说,指向基类对象的指针变量也可以指向派生类对象。
例定义一个基类Student(学生),再定义Student类的公用派生类Graduate(研究生), 用指向基类对象的指针输出数据。

#include <iostream>
#include <string>

using namespace std;
class Student//声明Student类
{
   public :
   Student(int, string,float );//声明构造函数
   void display( );//声明输出函数
   private :
   int num;
   string name;
   float score;
};
Student::Student(int n, string nam,float s)  //定义构造函数
{
   num=n;
   name=nam;
   score=s;
}
void Student::display( )//定义输出函数
{
   cout<<endl<<″num:″<<num<<endl;
   cout<<″name:″<<name<<endl;
   cout<<″score:″<<score<<endl;
}
class Graduate:public Student//声明公用派生类Graduate
{
   public :
   Graduate(int, string ,float ,float );//声明构造函数
   void display( );//声明输出函数
   private :
   float pay;//工资
};
Graduate::Graduate(int n, string nam,float s,float p):Student(n,nam,s),pay(p){ }//定义构造函数
void Graduate::display() //定义输出函数
{
   Student::display(); //调用Student类的display函数
   cout<<″pay=″<<pay<<endl;
}
int main()
{
   Student stud1(1001,″Li″,87.5); //定义Student类对象stud1
   Graduate grad1(2001,″Wang″,98.5,563.5); //定义Graduate类对象grad1
   Student *pt=&stud1;//定义指向Student类对象的指针并指向stud1
   pt->display( ); //调用stud1.display函数
   pt=&grad1; //指针指向grad1
   pt->display( ); //调用grad1.display函数
}

很多读者会认为: 在派生类中有两个同名的display成员函数,根据同名隐藏的规则,被调用的应当是派生类Graduate对象的display函数,
在执行Graduate::display函数过程中调用Student::display函数,输出num,name,score,然后再输出pay的值。

事实上这种推论是错误的,先看看程序的输出结果:

num:1001
name:Li
score:87.5
num:2001
name:wang
score:98.5
并没有输出pay的值。

问题在于pt是指向Student类对象的指针变量,它的指类是Student类,即使让它指向了grad1,但实际上pt指向的是grad1中从基类继承的部分(它指向的空间只能是基类中数据成员那么大的空间)。通过指向基类对象的指针,只能访问派生类中的基类成员,而不能访问派生类增加的成员。所以pt->display()调用的不是派生类Graduate对象所增加的display函数,而是基类的display函数,所以只输出研究生grad1的num,name,score3个数据。

其实,通过强制转换也可以将Student类的地址赋值给Graduate类所定义的指针,但是,这样做不安全,会让使用者误以为可以调用Graduate类中增加的成员,其实不然,所以不建议使用

综上所述,主要是因为基类和派生类中成员所占空间大小的不同,所引发的赋值兼容问题,例如int类型赋值给double类型,就是赋值兼容问题,而double类型赋值给int类型,就是不兼容,必须要强转,不然会报错

原文链接:https://blog.csdn.net/ilovekobemusic/article/details/8839371

原文地址:https://blog.51cto.com/14233078/2457617

时间: 2024-10-17 14:42:33

赋值兼容规则(C++)的相关文章

【总结】C++基类与派生类的赋值兼容规则

在初步探索了C++继承的语言特性之后,总结下其赋值兼容规则: 1.子类对象可以赋值给父类对象(切割/切片) 在公有继承的前提下,子类是可以赋值给父类对象的,为什么是共有继承(public),因为公有继承会产生"is-a"的关系,这种关系会导致子类中有结构的嵌套这父类的信息,.所以子类可以给父类赋值,期间会发生类似降级的事情,使得赋值成功.若为私有继承,则会产生"has-a"的关系,这种关系是从属关系,基类中的数据仅仅是包含在派生类中,若赋值,则不会产生类似于降级的事

(继承及其访问限定符)&&(派生类及其默认成员函数)&&(赋值兼容规则)

◆继承: ★继承概念 继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能.这样产生新的类,称派生类.继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程. 继承定义格式 ★继承关系&访问限定符 class Base { public: Base() { cout<<"B()" <<endl; } ~Base () { cout<<"~

C++:同名隐藏和赋值兼容规则

一.同名隐藏 同名隐藏,即在C++的继承中,只要子类的函数名和父类的函数名相同,子类中的函数将会隐藏所有父类中和子类的成员函数同名的函数 特别注意: 和函数之间的重载不同,这里只要求函数的名字相同,而对函数的参数列表是否相同不做要求.话句话说父类中和子类的成员函数名相同但参数列表不同的成员函数也会被隐藏 示例: 1 #include<iostream> 2 using namespace std; 3 class Father{ //父类 4 public: 5 Father()=defaul

C++语言笔记系列之十六——赋值兼容规则&amp;多继承的二义性

1.赋值兼容规则 (1)派生类对象可以给基类对象赋值,这种情况下派生类对象将从基类继承的成员的值赋值给一个基类对象:但是不允许将一个基类的对象赋值给一个派生类. (2)可以将派生类对象的地址赋给基类指针,使基类指针指向派生类对象,通过基类指针引用成员时只可以引用派生类从基类继承而来的成员,而不允许引用派生类的新成员. (3)引用与指针相同. 2.多继承 (1)一个派生类从两个以上的基类中去继承. (2)说明: class 派生类名:继承方式 基类1, 继承方式 基类2,...... {派生类成员

【继承与多态】C++:继承中的赋值兼容规则,子类的成员函数,虚函数(重写),多态

实现基类(父类)以及派生类(子类),验证继承与转换--赋值兼容规则: 子类对象可以赋值给父类对象(切割/切片) 父类对象不能赋值给子类对象 父类的指针/引用可以指向子类对象 子类的指针/引用不能指向父类对象(可以通过强制类型转换完成) #include<iostream> using namespace std; class People    //父类或者基类 { public:     void Display()     {         cout << "_na

(继承及其访问限定符)&amp;&amp;(派生类及其默认成员函数)&amp;&amp;(赋值兼容规则)

◆继承: ★继承概念 继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能.这样产生新的类,称派生类.继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程. 继承定义格式 ★继承关系&访问限定符 class Base { public: Base() { cout<<"B()" <<endl; } ~Base () { cout<<"~

006 子类父类赋值兼容规则

子类和父类的赋值兼容规则 1.同名隐藏(非常重要) 当子类的成员方法(show)和父类的成员方法(show)的名字相同的时候,父类的所有(show)方法,都不能用子类的对象来调用了,这种现象就是同名隐藏. #include <iostream> using namespace std; class Base{ public: Base():d(0){} ~Base(){} void show(){ cout << "Base show" << end

[c++]基类对象作为函数參数(赋值兼容规则)

编程处理教师的基本情况. 要求: 1.定义一个"person"类.用来存储及处理人的姓名.性别.年龄,成员函数自定: 2.定义"teacher"类,公有继承"person"类用来存储教师所在学院.所学专业.学历.学位.职称.教龄等,成员函数自定. 3.处理程序,主要包含: ⑴显示姓名.性别.年龄函数:既能显示person对象的姓名.性别.年龄,又能显示teacher对象的姓名.性别.年龄(用person引用对象为形參): ⑵显示教师所在学院.所学

[c++]基类对象作为函数参数(赋值兼容规则)

编程处理教师的基本情况.要求: 1.定义一个"person"类,用来存储及处理人的姓名.性别.年龄,成员函数自定: 2.定义"teacher"类,公有继承"person"类用来存储教师所在学院.所学专业.学历.学位.职称.教龄等,成员函数自定. 3.处理程序,主要包括: ⑴显示姓名.性别.年龄函数:既能显示person对象的姓名.性别.年龄,又能显示teacher对象的姓名.性别.年龄(用person引用对象为形参): ⑵显示教师所在学院.所学专