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

【30】C++子类相关

子类型关系

什么是子类型

公有继承时,派生类的对象可以作为基类的对象处理,派生类是基类的子类型。

 

#include <iostream>

using namespace std;

class A {
public:
	A() {}
	~A() {}
	void kill() { cout << "A kill." << endl; }
};

class B : public A {
public:
	B(){}
	~B(){}
	void kill() { cout << "B kill." << endl; }
};

void test(A a) {
	a.kill();  //调用的是A类对象的kill方法
}

int main(void) {
	A a;
	B b;
	test(a);
	test(b);

	system("pause");
	return 0;
}

子类型关系具有单向传递性。

C类是B类的子类型 

B类是A类的子类型

子类型的作用

在需要父类对象的任何地方, 可以使用”公有派生”的子类的对象来替代,

从而可以使用相同的函数统一处理基类对象和公有派生类对象

即:形参为基类对象时,实参可以是派生类对象

#include <iostream>
#include <sstream>

using namespace std;

class Father {
public:
	void play() {
		cout << "KTV唱歌!" << endl;
	}
};

class Son : public Father {
public:
	void play() {
		cout << "今晚吃鸡!" << endl;
	}
};


void party(Father *f1, Father *f2) {
	f1->play();
	f2->play();
}

int main(void) {
	Father yangKang;
	Son yangGuo;

	party(&yangKang, &yangGuo);

	system("pause");
	return 0;
}

执行:

KTV唱歌!

KTV唱歌!

注意:如果把Son改为protected继承,或private继承,就会导致编译失败!

子类型的应用 

1.基类(父类)的指针,可以指向这个类的公有派生类(子类型)对象。

Son yangGuo;

Father * f = &yangGuo;

2.公有派生类(子类型)的对象可以初始化基类的引用

Son yangGuo;

Father &f2 = yangGuo;

3.公有派生类的对象可以赋值给基类的对象

Son yangGuo;

Father f1 = yangGuo;

注意:以上的应用,反过来就会编译失败!

 

多重继承

什么是多重继承 

多继承/多重继承:

一个派生类可以有两个或多个基类(父类)。

多重继承在中小型项目中较少使用,在Java、C#等语言中直接取消多继承, 以避免复杂性.

 多重继承的用法

将多个基类用逗号隔开.

实例:

例如已声明了类A、类B和类C,那么可以这样来声明派生类D:

class D: public A, private B, protected C{
    //类D自己新增加的成员
};

D 是多继承形式的派生类,

D 有3个父类(基类)

它以公有的方式继承 A 类,

以私有的方式继承 B 类,

以保护的方式继承 C 类。

D 根据不同的继承方式获取 A、B、C 中的成员.

多继承的构造函数

多继承形式下的构造函数和单继承形式基本相同.

以上面的 A、B、C、D 类为例,D 类构造函数的写法为:

D(形参列表): A(实参列表), B(实参列表), C(实参列表){
    //其他操作
}

多继承的构造函数的调用顺序:

基类构造函数的调用顺序和和它们在派生类构造函数中出现的顺序无关,而是和声明派生类时基类出现的顺序相同。

多重继承的弊端: 二义性

// 解决多重继承的二义性的方法1:
	// 使用 "类名::" 进行指定, 指定调用从哪个基类继承的方法!
    wsc.Father::dance();
	wsc.Mother::dance();

	// 解决多重继承的二义性的方法2:
	// 在子类中重新实现这个同名方法, 并在这个方法内部, 使用基类名进行限定, 
// 来调用对应的基类方法
	wsc.dance();

 虚基类

问题

#include <iostream>	
#include <string>
#include <Windows.h>

using namespace std;

// 电话类
class Tel {
public:
	Tel() {
		this->number = "未知";
	}
protected:
	string number; //电话号码;
};

// 座机类
class FixedLine : public Tel {

};

// 手机类
class MobilePhone :public Tel {

};

// 无线座机
class WirelessTel :public FixedLine, public MobilePhone {
public:
	void setNumber(const char *number) {
		//this->number = number;   //错误, 指定不明确
		this->FixedLine::number = number;  //this可以省略
	}
	string getNumber() {
		//return MobilePhone::number;
		return MobilePhone::number;
	}
};

int main(void) {
	WirelessTel phone;
	phone.setNumber("13243879166");
	cout << phone.getNumber() << endl;  //打印未知
	system("pause");
	return 0;
}

输出:未知

解决

#include <iostream>	
#include <string>
#include <Windows.h>

using namespace std;

// 电话类
class Tel {   //虚基类
public:
	Tel() {
		this->number = "未知";
	}
protected:
	string number; //电话号码;
};

// 座机类
class FixedLine : virtual public Tel {  //虚继承

};

// 手机类
class MobilePhone : virtual public Tel { //虚继承

};

// 无线座机
class WirelessTel :public FixedLine, public MobilePhone {
public:
	void setNumber(const char *number) {
		this->number = number;  //直接访问number
	}
	string getNumber() {
		return this->number;   //直接访问number
	}
};

int main(void) {
	WirelessTel phone;
	phone.setNumber("13243879166");
	cout << phone.getNumber() << endl;
	system("pause");
	return 0;
}

输出:13243879166

常见错误总结

默认访问权限和语法要求

默认访问权限是private

访问权限之后一定要加冒号:

指定为某种访问权限之后, 就一直是这种权限, 除非再次指定为其他权限.

类的成员的访问权限, 与继承方式的区别

相同点:都有public,  private, protected

不同点:意义完全不同。

小结:

成员的访问权限:

public,  可以通过外部来访问(通过对象直接访问), 类似于C语言结构体中的成员

private, 只能在内部访问(在这个类的成员函数内访问),但是在子类的内部不能直接访问。

protected, 只能在内部访问,而且可以在子类的内部直接访问。

继承方式:

public, 父类成员, 被继承到子类后,访问权限都不变。

private, 父类成员, 被继承到子类后,访问权限都变为private

protected, 父类成员, 被继承到子类后,public权限的成员,降级为protected, 其他不变。


http://www.kler.cn/a/370724.html

相关文章:

  • 鸿蒙动态路由实现方案
  • 从玩具到工业控制--51单片机的跨界传奇【3】
  • Python操作Excel——openpyxl使用笔记(3)
  • SQL Server 导入Excel数据
  • AWTK fscript 中的 输入/出流 扩展函数
  • 【Idea启动项目报错NegativeArraySizeException】
  • 大数据日志处理框架ELK方案
  • SpringBoot使用JpaRepository方法命名和@Query查询的一些复杂场景
  • js 简单模拟JSON.stringify 功能
  • 初始JavaEE篇——多线程(4):wait、notify,饿汉模式,懒汉模式,指令重排序
  • [vulnhub]Kioptrix: Level 1.2 (#3)
  • 2024年9月电子学会青少年软件编程Python等级考试(三级)真题试卷
  • 赛博威携手百度智能云,开启数字营销新未来
  • Docker Compose一键部署Spring Boot + Vue项目
  • CSS3新增长度单位
  • 在Ubuntu(Linux)系统下安装Anaconda3
  • Kubernetes固定Pod IP和Mac地址
  • 手机号二要素核验 API 对接说明
  • 【04】RabbitMQ的集群机制
  • Ajax:表单 模板引擎
  • smuge error
  • 2025秋招八股文--服务器篇
  • 我接触csdn中的c++的时间
  • 简记Vue3(二)—— computed、watch、watchEffect
  • 【蓝桥杯选拔赛真题78】python电话号码 第十五届青少年组蓝桥杯python选拔赛真题 算法思维真题解析
  • 使用 FastGPT 工作流实现 AI 赛博算卦,一键生成卦象图