C++类的组合、前向引用声明
3.5类的组合
Part1.应用背景
对于复杂的问题,往往可以逐步划分为一系列稍微简单的子问题。
解决复杂问题的有效方法是将其层层分解为简单的问题组合,首先解决简单问题复杂问题也就迎刃而解了。
在面向对象的程序设计中,可以对复杂对象进行分解、抽象,把一个复杂对象分解为简单对象的组合,由比较容易理解和实现的部件对象装配而成。
Part2.定义及代码
①定义:类的组合描述的就是一个雷内嵌其他类的对象作为成员的情况,他们之间的关系是一种包含与被包含的关系。
②作用机制:当创建类的对象时,如果这个类具有内嵌对象成员,那么各个内嵌对象将首先被自动创建。
在创建对象时既要对本类的基本类型数据成员进行初始化又要对内嵌对象成员进行初始化。
③一般形式:
类名::类名(形参表):内嵌对象1(形参表),内嵌对象2(形参表),......
//内嵌对象1(形参表),...称作 初始化列表:对内嵌对象进行初始
{
类的初始化
}
④组合类的构造函数、析构函数调用顺序:
构造函数调用顺序:
1)调用内嵌对象的构造函数,调用顺序按照内嵌对象在组合类的定义中出现的次序。
注意:内嵌对象在构造函数的初始化类表中出现的顺序与内嵌对象构造函数的调用顺序无关。
2)执行本类构造函数的函数体。
析构函数调用顺序:
析构函数的调用执行顺序与构造函数刚好相反。
例:
#include<iostream>
using namespace std;
class Mammal{
public:
Mammal()
{
cout << "Constructing Mammal." << endl;
}
~Mammal()
{
cout << "Desstructing Mammal." << endl;
}
};
class Dog :public Mammal {
public:
Dog()
{
cout << "Constructing Dog." << endl;
}
~Dog()
{
cout << "Desstructing Dog." << endl;
}
};
void main()
{
Dog d;
}

⑤组合类的复制构造函数
//类的组合,线段(Line)类
//使用一个类来描述线段,Point类的对象来表示端点,使Line类包括Point类的两个对象p1,p2,作为其数据成员。
//Line类具有计算线段长度的功能,在构造函数中实现
#include<iostream>
#include<cmath>
using namespace std; class Point {
public:
Point(int xx = , int yy = ) {//构造函数
x = xx;
y = yy;
}
Point(Point& p);//复制构造函数
int getX() { return x; }
int getY() { return y; }
private:
int x, y;
};
Point::Point(Point& p) {//复制构造函数的实现
x = p.x;
y = p.y;
cout << "Calling the copy constructor of Point" << endl;
}
//类的组合
class Line {
public:
Line(Point xp1, Point xp2);
Line(Line& l);
double getLen() { return len; }
private:
Point p1, p2;//Point类的对象p1,p2
double len;
};
//组合类的构造函数
Line::Line(Point xp1, Point xp2) :p1(xp1), p2(xp2) {
cout << "Calling constructor of Line" << endl;
double x = static_cast<double>(p1.getX() - p2.getX());
double y = static_cast<double>(p1.getY() - p2.getY());
len = sqrt(x * x + y * y);
}
//组合类的复制构造函数
Line::Line(Line& l) :p1(l.p1), p2(l.p2) {
cout << "Calling the copy constructor of Line" << endl;
len = l.len;
}
//主函数
int main()
{
Point myp1(, ), myp2(, );//建立Point类的对象
Line line(myp1, myp2);//建立Line类的对象
Line line2(line);//利用复制构造函数建立一个新对象
cout << "The length of the line is:";
cout << line.getLen() << endl;
cout << "The length of the line2 is:";
cout << line2.getLen() << endl;
return ;
}

分析:
主程序执行时,首先生成连个Point类的对象,然后构造Line类的对象line,接着通过复制构造函数建立Line类的第二个对象line2,最后输出两点的距离。
整个过程中,Point类的复制构造函数被调用了六次,而且都是在Line类构造函数体运行之前进行的,他们分别是两个对象在Line构造函数进行函数参数形实结合时,初始化内嵌对象时,以及复制构造函数line2时被调用的。两点的距离在Line类的构造函数中求得,存放在其私有数据成员len中,只能通过成员函数getLen()来访问。
3.6前向引用声明
Part1.应用场景
C++的类应该先定义再使用,但是在处理相对复杂的问题是,考虑类的组合时,很有可能遇到两个类相互引用的情况,这种情况也称为循环依赖。
因此,无论将哪一个类的定义放在前面,都会引起编译错误。
解决这种问题的方法,就是使用前向引用声明。
Part2.定义及代码
①定义:前向引用声明,是在引用未定义的类之前,将该类的名字告诉编译器,使编译器根据知道那是一个类名。
②例:
class B;//前向引用声明
class A{//A类的定义
public:
void f(B b);//以B类对象b为形参的成员函数
};
class B{//B类的定义
public:
void g(A a);//以A类对象a为形参的成员函数
};
③注意:前向引用声明不是万能的。
class Frred;//前向引用声明
class Barney{
Fred x;//错误:类Fred的声明尚不完善,不能定义类Fred的数据成员
};
class Fred{
Barney y;
}
错误:对类的前向引用声明只能说明Fred是一个类名,而不能给出该类的完整定义,因此在类Barney中就不能定义类Fred的数据成员。
class Frred;//前向引用声明
class Barney{
public:
...
void method(){//错误:Fred类的对象在定义前被使用
x.yabbaDabbaDo;
}
private:
Fred &x;//正确:经过前向引用声明,可以声明Fred类的对象引用或指针
};
class Fred{
public:
...
void yaabaDabbaDo();
private:
Barney &y;
};
错误:编译时指出错误,因为在类Barney的内联函数中使用了有x所指向的、Fred类的对象,而此时Fred类尚未被完整的定义。
解决方法:更改这两个类的定义次序,或者将函数method()改为非内联形式,并且在类Fred的完整定义之后,再给出函数定义。
C++类的组合、前向引用声明的更多相关文章
- vs2015类中方法前的引用链接不显示的解决方案
在工具→选项,打开如下界面,寻找“文本编辑器→所有语言”中设置显示:<img data-rawheight="761" data-rawwidth="130 ...
- C++中对类的提前引用声明注意事项
//或许,友元是VC++6.0心里永远的痛,对于这个BUG我一直很介意.//注:这个程序在VC++6.0里是行不通的,在VS2008里是可以的.#include <iostream> #i ...
- vs2017如何设置类或函数前不显示引用的数量
这几天,从vs2013换成vs2017,17版本增加了一个类或函数前提示引用的数量,这个感觉很别扭,如何取消显示这个呢? 问题如下: 取消显示这个引用的步骤: 找到菜单栏: 工具 ---> 选项 ...
- vs2015如何设置类或函数前不显示引用的数量
这几天,从vs2012换成vs2015,感觉15版本增加了一个类或函数前提示引用的数量,这个感觉很别扭,如何取消显示这个呢? 问题如下: 取消显示这个引用的步骤: 找到菜单栏: 工具 ---> ...
- 类声明、类作用域、前向声明、this指针、嵌套类、PIMPL 技法 等
一.类声明 //类是一种用户自定义类型,声明形式: class 类名称 { public: 公有成员(外部接口) private: 私有 ...
- c++基础语法 构造函数 析构函数 类的组合
1 构造函数 1.不能指定任何返回值,甚至连void都不能有. 2.与Java不同,c++不同new对象,对于无参的构造函数声明对象时括号应该省略. 2 析构函数 1. 前加~,不能有参数,不能有返回 ...
- 【C++基础】类的组合
所谓类的组合是指:类中的成员数据是还有一个类的对象或者是还有一个类的指针或引用.通过类的组合能够在已有的抽象的基础上实现更复杂的抽象. 比如: 1.按值组合 #include<iostream. ...
- Java编程的逻辑 (14) - 类的组合
本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http: ...
- java 报错非法的前向引用
今天在看<thinking in java>的时候,第四章提到了非法的前向引用,于是自己试了一下,书中的例子倒是一下就明白了,但是自己写的一个却怎么也不明白,于是上网问了一位前辈,终于明白 ...
随机推荐
- urql 高度可自定义&&多功能的react graphql client
urql 是一个很不错的graphql client,使用简单,功能强大,通过exchanges 实现了完整的自定义特性 通过urql 的exchanges 我们可以实现灵活的cache策略 参考资料 ...
- HTML5 Geolocation(地理定位)
一.背景 在HTML规范中,增加了获取用户地理信息的API,这样使得可以基于用户位置开发互联网应用,即基于位置服务 鉴于该特性可能侵犯用户的隐私,除非用户同意,否则用户位置信息是不可用的. Inter ...
- [USACO09DEC] Dizzy Cows 拓扑序
[USACO09DEC] Dizzy Cows 拓扑序 先对有向边跑拓扑排序,记录下每个点拓扑序,为了使最后的图不存在环,加入的\(p2\)条无向边\(u,v\)必须满足\(u\)拓扑序小于\(v\) ...
- 虚拟变量陷阱(Dummy Variable Trap)
虚拟变量陷阱(Dummy Variable Trap):指当原特征有m个类别时,如果将其转换成m个虚拟变量,就会导致变量间出现完全共线性的情况. 假设我们有一个特征“性别”,包含男性和女性两个类别,如 ...
- win服务器 文件上传下载出现“未指定的错误” 解决方法汇总
环境 WIN平台IIS服务器 经常出现于ASPX页面 汇总 1.权限问题 出现场景 : 基于ACCESS数据库 原因解析 : 1.首先需要排除自身问题,例如建表使用关键字,格式错误,插入数据与 ...
- uwsgi example
ref (uwsgi unix socket example) cat /etc/os-release curl --version # curl sudo pip install uwsgi e ...
- Sybase数据库连接配置
简介 1984年,Mark B. Hiffman和Robert Epstern创建了Sybase公司,并在1987年推出了Sybase数据库产品.SYBASE主要有三种版本,一是UNIX操作系统下运行 ...
- 第12组 Alpha冲刺(4/6)
Header 队名:To Be Done 组长博客 作业博客 团队项目进行情况 燃尽图(组内共享) 由于这两天在修bug,燃尽图没有下降 展示Git当日代码/文档签入记录(组内共享) 注: 由于Git ...
- Hadoop(二)—— HDFS
HDFS(Hadoop Distributed File System)Hadoop分布式文件系统. 一.HDFS产生的背景 随着数据量越来越大,如果大到一台主机的磁盘都存放不下,该如何解决这个问题. ...
- 安装关系型数据库MySQL和大数据处理框架Hadoop
1. 简述Hadoop平台的起源.发展历史与应用现状.列举发展过程中重要的事件.主要版本.主要厂商:国内外Hadoop应用的典型案例. (1)Hadoop的介绍: Hadoop最早起源于Nutch,N ...