C++类型兼容规则

一、概念


类型兼容规则是指在需要基类对象的任何地方,都可以使用公有派生类的对象来替代。通过公有继承,派生类得到了基类中除构造函数、析构函数之外的所有成员。这样,公有派生类实际就具备了基类的所有功能,凡是基类能解决的问题,公有派生类都可以解决。


再来看一下派生类中从基类中继承而来的成员和新增成员的关系:


在这里插入图片描述


虽然这个不是实际的物理模型,但是起码我们能大致明白两者的关系,同时也可以发现,派生类其实是可以被当作基类来使用的,因为它拥有基类的几乎所有成员(除了构造、析构函数)。
而实际上在基类与派生类之间存在一种转换,即派生类到基类类型转换。和其他类型转换一样,编译器会隐式地执行派生类到基类的转换
存在如下三种转换:

  • 派生类的对象可以隐含转换为基类对象。
  • 派生类的对象可以初始化基类的引用。
  • 派生类的指针可以隐含转换为基类的指针。

二、代码

#include <iostream>
using namespace std;
class A {
	public:
		A() = default;
		A(int a1, int b1) : a(a1), b(b1) { }
		~A() { }
		void print1() const{cout << a << ' ' << b << endl;}
		int a = 0, b = 0;
};
class B : public A {
	public:
		B() = default;
		B(int a1, int b1, const string s1) : A(a1, b1), s(s1) { }
		B(B &item) {
			this->a = item.a;
			this->b = item.b;
			this->s = item.s;
		}
		~B() { }
		void print2() const{this->print1(); cout << s << endl;}
	private:
		string s = "abc";
};
void display1(A &item) {
	item.print1();
}
void display2(A *ptr) {
	ptr->print1();
}
int main() {
	A a1(1, 1);   
	B b1(1, 2, "def");      
	A a2(b1);   //基类的对象可以用来初始化派生类的对象
	display1(b1);   //参数类型为基类对象的函数同样也可以使用派生类的对象作为参数
	A &quote1 = b1;  //基类的引用可以绑定派生类对象
	A *ptr1 = &b1;   //基类的对象指针同样可以指向派生类对象的地址
	display2(ptr1);
	return 0;
}

该程序定义了两个类,基类A和派生类B。
然后还有两个函数display1和display2,两个函数的参数类型分别是基类对象的引用还有基类的对象指针。
在主函数中我们可以发现:
在这里插入图片描述


三、注意事项和总结


我们需要尤其注意的是,不存在从基类向派生类的隐式类型转换


A base;
B *ptr = &base;  //错误:不能将基类转换成派生类
B &quote = base; //错误:不能将基类转换成派生类

上述的两种转换都想从基类向派生类转换,是错误的。如果上述赋值是合法的,则我们有可能会使用ptr指针或者quote引用访问base中本不存在的成员。
除此之外:
在这里插入图片描述


类型兼容的好处是对于基类及其公有派生类的对象,可以使用相同的函数统一进行处理。因为当函数的形参为基类的对象(或引用、指针)时,实参可以是派生类的对象(或指针),而没有必要为每一个类设计单独的模块,大大提高了程序的效率。


笔记中大部分内容引用自《C++语言程序设计》和《C++ Primer》

posted @ 2021-11-11 16:40  Dawnlight-_-  阅读(255)  评论(0编辑  收藏  举报