当前课程知识点:C++语言程序设计基础 > 第4章 类与对象 > 类的组合 > 类的组合
类中的成员是另一个类的对象。
可以在已有抽象的基础上实现更复杂的抽象。
原则:不仅要负责对本类中的基本类型成员数据初始化,也要对对象成员初始化。
声明形式:
类名::类名(对象成员所需的形参,本类成员形参)
:对象1(参数),对象2(参数),......
{
//函数体其他语句
}
首先对构造函数初始化列表中列出的成员(包括基本类型成员和对象成员)进行初始化,初始化次序是成员在类体中定义的次序。
成员对象构造函数调用顺序:按对象成员的声明顺序,先声明者先构造。
初始化列表中未出现的成员对象,调用用默认构造函数(即无形参的)初始化
处理完初始化列表之后,再执行构造函数的函数体。
大家好
欢迎回来继续学习
C++语言程序设计
这一节呢
我们来学习类的组合
我们知道在制造业
多年来都一直使用
部件组装的生产方式
部件组装的生产方式呢
比一切手工从头做起
它的生产效率肯定是要高
产品呢
它的标准化 它的可靠性
也都更好
程序中我们是不是也可以
借用这种部件组装的思想呢
我们能不能用已经存在的这些类
去组装新的类呢
C++程序是可以这样的
C++语言支持类的组合
也就是说
我们在定义一个新类的时候
可以让它的类成员
是已有类的对象
也就是说
一些类的对象
可以作为另外一个类的部件
那么这个就是类的组合
类组合的基本概念就是
类中的成员
是另外其他类的对象
这样我们就可以在
已有的抽象基础上
实现更复杂的抽象
其实组合类的定义是很简单的
但是有一个问题
组合类的构造函数怎么设计呢
我们知道每个类的构造函数
都是负责自己本类成员初始化的
如果说我们用另外类的对象
作为新定义类的成员
那我们想一想
这个组合类有没有权利去访问
部件对象内部的私有成员呢
显然是没有权利访问的
因为一个类的私有成员
只有这个类内部的函数可以访问
类外任何地方是不可以访问的
而且部件类的设计者 开发者
跟组合类的设计者 开发者
可能不是一个人
甚至不是一个团队
那么这个时候
你怎么知道部件类
有哪些私有成员
你怎么能知道如何去写代码
初始化这些成员呢
显然是不行的
其实在制造业也是这样
我们买来部件 然后就组装
一般来讲
这个部件我们不会去拆开它
去修改它
而是直接拿来组装
程序中也是这样的道理
那么这些部件对象
它们的初始化怎么实现呢
这就要在写组合类
构造函数的时候
考虑到这个问题
要有组合类的构造函数
负责将部件对象初始化
所需要的初始化参数传递给它
然后呢
编译器会自动去调用部件类的
构造函数
来初始化这些部件对象
现在我们来看一下
这个组合类构造函数
它的语法形式应该是什么样的
我们来看
在这个组合类构造函数中
它的参数表中
就要多列一些参数
很可能需要多列一些参数
为什么呢
因为参数表中不仅要给出
初始化本类
基本类型数据成员的这些参数
还要考虑类中那些对象成员
他们怎么初始化
这些对象成员的初始化
会自动调用
它所属类的构造函数来完成
但是这些构造函数
它是需要参数的
这些参数有谁传给它呢
就由组合类的构造函数传给它
所以我们看
在这里初始化列表中
列出一个个的部件对象
在部件对象后面括号里面
要列出这些部件对象初始化
所需要的参数
现在我们来考虑
当有组合的时候
组合类的对象
它初始化的时候
这些构造次序
初始化次序是什么呢
现在我们就来看一看
组合类对象构造的时候
是按照什么样的次序来初始化的
首先
要对构造函数的初始化列表中
列出的成员
包括基本类型的成员
也包括对象成员进行初始化
那么类里面有那么多成员
都在初始化列表里列出来
谁先谁后呢
先初始化哪个呢
这个初始化次序
并不按照你初始化列表里的
列的次序来执行
而是按照成员在类体中
定义的次序来执行
也就是说
你的数据成员
谁定义在前
谁就初始化在前
谁定义在后
谁就后初始化
那么成员对象
它的构造函数调用的顺序
也是按照这些成员对象
在类体中声明的顺序来的
那么有的成员对象
可能你在初始化列表中
没有给列出来
那它怎么初始化呢
如果你在初始化列表中
没有列出某些成员对象
那这些成员对象初始化的时候
就要调用它自己所属类的
默认构造函数
也就是不需要形参的构造函数
来进行初始化
当整个初始化列表
都处理完了之后
才会执行构造函数的函数体
那么现在
我们来考虑这样一个问题
如果作为部件对象的
它的所属类
没有定义默认构造函数
那你在初始化
这个组合类对象的时候
是不是就必须得给这个部件
对象的初始化传递参数啊
如果部件对象没有默认构造函数
也就是说
它的构造必须要参数
那组合类它的构造函数
就必须给它传参数
这个时候如果你不给它传参数
编译的时候编译器就会报错
说找不到它的默认构造函数
所以呢返回来想
如果你写一个类
希望它非常通用
希望它经常能够被重用
能够用在很多场合 很多地方
那你就要记住
不管你给它写了多少个构造函数
记住 再多写一个
不要参数的默认构造函数
因为当这个类的对象
被用作其他类的部件成员的时候
可能那个组合类
根本就不写构造函数
就用默认构造函数
有没有这个可能
当然有这个可能
如果组合类根本就不写构造函数
那它还能给部件对象
传什么参数吗
肯定就不会传参数了
这个时候就需要它的部件对象
一定得有默认构造函数
当然了 我们写组合类的时候
也会去参照它部件对象
所属类的相关的接口说明
去看看它是不是需要传参数
这些两方面都兼顾到
我们才能够顺利地去重用
已经定义好的类
-导学
--第1章导学
-计算机系统简介
--计算机系统简介
--计算机系统简介 测试题
-计算机语言和程序设计方法的发展
--计算机语言和程序设计方法的发展 测试题
-面向对象的基本概念
--面向对象的基本概念 测试题
-程序的开发过程
--程序的开发过程
--程序的开发过程 测试题
-信息的表示和储存
--计算机的数字系统
--数据的编码表示
--信息的表示和储存 测试题
-实验指导
-导学
--第二章导学
-C++语言概述
--C++语言概述 测试题
-基本数据类型、常量、变量
--程序举例
--基本数据类型、常量、变量 测试题
-运算与表达式
--运算与表达式 测试题
-实验二:简单程序设计(上)
-数据的输入和输出
--数据的输入和输出
--数据的输入和输出 测试题
-选择结构
--if语句
--switch语句
--选择结构 测试题
-循环结构
--for语句
--循环结构 测试题
-自定义类型
--自定义类型
--自定义类型
-第2章小结
--第二章小结
-实验二:C++简单程序设计(下)
-导学
--导学
-函数定义
--函数定义
--函数定义 测试题
-函数调用
--例3-2
--例3-3
--例3-4
--例3-5
--例3-6
--函数调用 测试题
-嵌套与递归
--例3-9
--例3-10
--嵌套与递归 测试题
-函数的参数传递
--函数的参数传递
--函数的参数传递 测试题
-引用类型
--引用类型 测试题
-含有可变参数的函数
--含有可变参数的函数 测试题
-内联函数
--内联函数 测试题
-constexpr函数
--CONSTEXPR函数课后习题
-带默认参数值的函数
--带默认参数值的函数 测试题
-函数重载
--函数重载 测试题
-C++系统函数
--C++系统函数习题
-第3章小结
--第三章小结
-实验三(上)函数的应用
-实验三(下)函数的应用
-导学
--导学
-面向对象程序的基本特点
--面向对象程序的基本特点 测试题
-类和对象
--类和对象的定义
--类和对象 测试题
-构造函数
--构造函数基本概念
--委托构造函数
--复制构造函数
--构造函数 测试题
-析构函数
--析构函数
--析构函数 测试题
-类的组合
--类的组合
--类的组合程序举例
--前向引用声明
--类的组合 测试题
-UML简介
--UML简介
--UML简介课后习题
-结构体与联合体
--结构体与联合体 测试题
-枚举类
--枚举类
--枚举类 测试题
-第4章小结
--第四章小结
-实验四(上)
--实验四(上)
-实验四(下)
--实验四(下)
-导学
--导学
-标识符的作用域与可见性
--标识符的作用域与可见性 测试题
-对象的生存期
--对象的生存期
--对象的生存期 测试题
-类的静态成员
--类的静态成员 测试题
-类的友元
--类的友元 测试题
-共享数据的保护
--共享数据的保护 测试题
-多文件结构和预编译命令
--多文件结构和预编译命令 测试题
-第5章小结
--小结
-实验五
--实验五
-导学
--导学
-数组的定义与初始化
--数组的定义与使用
--一维数组应用举例
--数组的定义与初始化 测试题
-数组作为函数的参数
--数组作为函数的参数 测试题
-对象数组
--对象数组
--对象数组 测试题
-基于范围的for循环
-指针的定义和运算
--指针的定义和运算 测试题
-综合实例
--综合实例
-实验六(上)
--实验六上
-指针与数组
--指针数组
--指针与数组 测试题
-指针与函数
--指针类型的函数
--指向函数的指针
--指针与函数 测试题
-对象指针
--对象指针
--对象指针 测试题
-动态内存分配
--动态内存分配 测试题
-智能指针
--智能指针
-vector对象
--vector对象
--vector对象 测试题
-对象复制与移动
--移动构造
--对象复制与移动 测试题
-字符串
--C风格字符串
--string类
--字符串 测试题
-第6章小结
--第六章小结
-综合实例
--综合实例
-实验六(下)
--实验六(下)