C++派生类与基类的转换规则_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中包含派生类中增加的成员
应当注意,子类型关系是单向的、不可逆的。B是A的子类型,不能说A是B的子类型。
只能用子类对象对其基类对象赋值,而不能用基类对象对其子类对象赋值,理由是显然的,因为基类对象不包含派生类的成员,无法对派生类的成员赋值。同理,同一基类的不同派生类对象之间也不能赋值。
派生类对象可以替代基类对象向基类对象的引用进行赋值或初始化。
如已定义了基类A对象a1,可以定义a1的引用变量:
A a1; //定义基类A对象a1
B b1; //定义公用派生类B对象b1
A& r=a1; //定义基类A对象的引用变量r,并用a1对其初始化
这时,引用变量r是a1的别名,r和a1共享同一段存储单元。也可以用子类对象初始化引用变量r,将上面最后一行改为
A& r=b1;//定义基类A对象的引用变量r,并用派生类B对象b1//对其初始化
或者保留上面第3行“A& r=a1;”,而对r重新赋值:
r=b1;//用派生类B对象b1对a1的引用变量r赋值
注意: 此时r并不是b1的别名,也不与b1共享同一段存储单元。它只是b1中基类部分的别名,r与b1中基类部分共享同一段存储单元,r与b1具有相同的起始地址。
如果函数的参数是基类对象或基类对象的引用,相应的实参可以用子类对象。如有一函数

复制代码 代码如下:

fun: void fun(A& r)//形参是类A的对象的引用变量
{
cout<<r.num<<endl;
} //输出该引用变量的数据成员num
函数的形参是类A的对象的引用变量,本来实参应该为A类的对象。由于子类对象与派生类对象赋值兼容,派生类对象能自动转换类型,在调用fun函数时可以用派生类B的对象b1作实参: fun(b1); 输出类B的对象b1的基类数据成员num的值。与前相同,在fun函数中只能输出派生类中基类成员的值。
派生类对象的地址可以赋给指向基类对象的指针变量,也就是说,指向基类对象的指针变量也可以指向派生类对象。
例11.10 定义一个基类Student(学生),再定义Student类的公用派生类Graduate(研究生), 用指向基类对象的指针输出数据。本例主要是说明用指向基类对象的指针指向派生类对象,为了减少程序长度,在每个类中只设很少成员。学生类只设num(学号),name(名字)和score(成绩)3个数据成员,Graduate类只增加一个数据成员pay(工资)。
程序如下:
[code]
#include <iostream>
#include <string>
Graduate::Graduate(int n, string nam,float s,float p):Student(n,nam,s),pay(p){ }
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;//工资
};
//定义构造函数
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类对象的指针变量,即使让它指向了grad1,但实际上pt指向的是grad1中从基类继承的部分。
通过指向基类对象的指针,只能访问派生类中的基类成员,而不能访问派生类增加的成员。所以pt->display()调用的不是派生类Graduate对象所增加的display函数,而是基类的display函数,所以只输出研究生grad1的num,name,score3个数据。
如果想通过指针输出研究生grad1的pay,可以另设一个指向派生类对象的指针变量ptr,使它指向grad1,然后用ptr->display()调用派生类对象的display函数。但这不大方便。
通过本例可以看到: 用指向基类对象的指针变量指向子类对象是合法的、安全的,不会出现编译上的错误。但在应用上却不能完全满足人们的希望,人们有时希望通过使用基类指针能够调用基类和子类对象的成员。
我们会在下一讲解决这个问题,办法是使用虚函数和多态性

时间: 2024-11-16 23:09:39

C++派生类与基类的转换规则_C 语言的相关文章

派生类对象如何访问基类的基类中被隐藏的同名函数成员

问题描述 派生类对象如何访问基类的基类中被隐藏的同名函数成员 #include <iostream> using namespace std; class Base0{ public: int var0; void Func(){ cout << "This is Func of Base0" << endl; } }; class Base1:public Base0{ public: int var1; void Func(){ cout <

C++中基类和派生类之间的转换实例教程_C 语言

本文实例讲解了C++中基类和派生类之间的转换.对于深入理解C++面向对象程序设计有一定的帮助作用.此处需要注意:本文实例讲解内容的前提是派生类继承基类的方式是公有继承,关键字public.具体分析如下: 以下程序为讲解示例: #include<iostream> using namespace std; class A { public: A(int m1, int n1):m(m1), n(n1){} void display(); private: int m; int n; }; voi

深入分析C++派生类中的保护成员继承_C 语言

protected 与 public 和 private 一样是用来声明成员的访问权限的.由protected声明的成员称为"受保护的成员",或简称"保护成员".从类的用户角度来看,保护成员等价于私有成员.但有一点与私有成员不同,保护成员可以被派生类的成员函数引用. 如果基类声明了私有成员,那么任何派生类都是不能访问它们的,若希望在派生类中能访问它们,应当把它们声明为保护成员.如果在一个类中声明了保护成员,就意味着该类可能要用作基类,在它的派生类中会访问这些成员.

python新手求助-Python3.x 检查一个类的基类

问题描述 Python3.x 检查一个类的基类 Python基础教程P123页检查类SPAMFilter的基类是这样做的 SPAMFilter._bases_ 但是我没找到这个属性,怎么回事?Python3.x取消了吗? 解决方案 查看u 一下官方文档就知道了.

详解C++编程中多级派生时的构造函数和访问属性_C 语言

C++多层派生时的构造函数 一个类不仅可以派生出一个派生类,派生类还可以继续派生,形成派生的层次结构.在上面叙述的基础上,不难写出在多级派生情况下派生类的构造函数. 通过例下面的程序,读者可以了解在多级派生情况下怎样定义派生类的构造函数.相信大家完全可以自己看懂这个程序. [例] 多级派生情况下派生类的构造函数. #include <iostream> #include<string> using namespace std; class Student//声明基类 { publi

派生-运用虚基类对公司员工管理系统 的实现

问题描述 运用虚基类对公司员工管理系统 的实现 设计一个利用文件处理方式实现对公司人员(包括工程师.领导和主任工程师)进行管理,要求具有增加数据.更新数据.查询数据.删除数据以及实现数据的功能. 实现提示: 设计一个虚基类Staff(员工),包含编号.姓名和年龄保护数据成员以及相关的成员函数:由Staff派生出工程师类Engineer,包含专业和职称保护数据成员以及相关的成员函数:再由Staff派生出领导类Leader,包含职务和部门保护数据成员以及相关的成员函数:然后由Engineer和Lea

浅谈C++基类的析构函数为虚函数_C 语言

1.原因: 在实现多态时, 当用基类指针操作派生类, 在析构时候防止只析构基类而不析构派生类. 2.例子: (1). #include<iostream> using namespace std; class Base{ public: Base() {}; ~Base() {cout << "Output from the destructor of class Base!" << endl;}; void DoSomething() { cout

C++中的类模板详解及示例_C 语言

C++中的函数模板 对于类的声明来说,也有同样的问题.有时,有两个或多个类,其功能是相同的,仅仅是数据类型不同,如下面语句声明了一个类: 复制代码 代码如下: class Compare_int{ public:  Compare(int a,int b)  {   x=a;   y=b;  }   int max()  {   return (x>y)?x:y;  }  int min()  {   return (x<y)?x:y;  } private:  int x,y;}; 其作用是

C语言 存储类详解及示例代码_C 语言

C 存储类 存储类定义 C 程序中变量/函数的范围(可见性)和生命周期.这些说明符放置在它们所修饰的类型之前.下面列出 C 程序中可用的存储类: auto register static extern auto 存储类 auto 存储类是所有局部变量默认的存储类. { int mount; auto int month; } 上面的实例定义了两个带有相同存储类的变量,auto 只能用在函数内,即 auto 只能修饰局部变量. register 存储类 register 存储类用于定义存储在寄存器