继承和构造函数语法造成的一个bug
一
- 出错误的代码
开发环境: visual studio 2017 社区版
#include "pch.h"
#include <iostream>
#include <string>
#include <list>
using namespace std;
//公司类 抽象类或接口
class Company
{
public:
Company() {}
Company(string str)
:name(str) {}
virtual void Add(Company* c) = 0; //增加
virtual void Remove(Company* c) = 0; //移除
virtual void Display(int depth) = 0; //显示
virtual void LineOfDuty() = 0; //履行职责
inline bool operator==(const Company& company) const
{
return this->name == company.name;
}
protected:
string name;
};
class ConcreteCompany : public Company
{
public:
ConcreteCompany(string name) : Company(name)
{
children = new list<Company*>;
}
void Add(Company* c) override
{
children->push_back(c);
}
void Remove(Company* c) override //删除子节点
{
for (list<Company*>::iterator it = children->begin(); it != children->end(); ++it)
{
if (*(*it) == *c)
{
children->erase(it);
break;
}
}
}
void Display(int depth) override //显示
{
for (int ix = 0; ix < depth; ++ix)
{
cout << "-";
}
cout << this->name << endl;
for (list<Company*>::iterator it = children->begin(); it != children->end(); ++it)
{
(*it)->Display(depth + 2);
}
}
virtual void LineOfDuty() override //履行职责
{
for (list<Company*>::iterator it = children->begin(); it != children->end(); ++it)
{
(*it)->LineOfDuty();
}
}
private:
list<Company*>* children;
};
//人力资源部 树叶节点
class HRDepartment : public Company
{
public:
HRDepartment(string str) : Company(name) {}
void Add(Company* c) override //增加
{
}
void Remove(Company* c) override //移除
{
}
void Display(int depth) override //显示
{
for (int ix = 0; ix < depth; ++ix)
{
cout << "-";
}
cout << name << endl;
}
void LineOfDuty() override //履行职责
{
cout << this->name << " 员工招聘培训管理" << endl;
}
};
class FinanceDepartment : public Company
{
public:
FinanceDepartment(string str) : Company(name) {}
void Add(Company* c) override //增加
{
}
void Remove(Company* c) override //移除
{
}
void Display(int depth) override //显示
{
for (int ix = 0; ix < depth; ++ix)
{
cout << "-";
}
cout << name << endl;
}
void LineOfDuty() override //履行职责
{
cout << this->name << " 公司财务收支管理" << endl;
}
};
int main()
{
Company* root = new ConcreteCompany("北京总公司");
root->Add(new HRDepartment("总公司人力资源部"));
root->Add(new FinanceDepartment("总公司财务部"));
ConcreteCompany* comp = new ConcreteCompany("上海华东分公司");
comp->Add(new HRDepartment("华东分公司人力资源部"));
comp->Add(new FinanceDepartment("华东分公司财务部"));
root->Add(comp);
ConcreteCompany* comp1 = new ConcreteCompany("南京办事处");
comp1->Add(new HRDepartment("南京办事处人力资源部"));
comp1->Add(new FinanceDepartment("南京办事处财务部"));
comp->Add(comp1);
ConcreteCompany* comp2 = new ConcreteCompany("杭州办事处");
comp2->Add(new HRDepartment("杭州办事处人力资源部"));
comp2->Add(new FinanceDepartment("杭州办事处财务部"));
comp->Add(comp2);
cout << "\n结构图" << endl;
root->Display(1);
cout << "\n职责:" << endl;
root->LineOfDuty();
return 0;
}
编译上述代码,VS2017提示错误
一开始这个错误让我百思不得其解,因此将同样的代码放到Linux下编译调试。g++提示的错误如下:
二
- 错误的解决
经过排查发现,错误出现在下面这两行代码
HRDepartment(string str) : Company(name) {}
FinanceDepartment(string str) : Company(name) {}
其中HRDepartment类和FinanceDepartment类均是继承自Company类,这两个类的构造函数初始化Company类中的成员name。正确的写法应该是
HRDepartment(string str) : Company(str) {}
FinanceDepartment(string str) : Company(str) {}
三 知识补充
- 派生类不能直接访问基类的私有成员,而必须通过基类方法进行访问。具体的说,派生类构造函数必须使用基类构造函数
- 创建派生对象时,程序首先创建基类对象,这意味着基类对象应当在程序进入派生类构造函数之前被创建。C++使用成员初始化列表语法来完成这种工作。
- 看下面一个例子
class TableTennisPlayer
{
private:
string firstname;
string lastname;
bool hasTable;
public:
TableTennisPlayer(const string &fn = "none",
const string &ln = "none", bool ht = false);
};
//基类的构造函数
TableTennisPlayer::TableTennisPlayer(const string & fn, const string & ln, bool ht)
:firstname(fn),lastname(ln),hasTable(ht)
{
}
class RatedPlayer : public TableTennisPlayer
{
public:
RatedPlayer(unsigned int r = 0, const string& fn = "none",
const string& ln = "none", bool ht = false);
private:
unsigned int rating; //派生类需要一个数据成员存储比分
};
//子类的构造函数
RatedPlayer::RatedPlayer(unsigned int r, const string & fn, const string & ln, bool ht)
:TableTennisPlayer(fn,ln,ht)
{
this->rating = r;
}
int main()
{
return 0;
}
先看RatedPlayer的一个构造函数
//子类的构造函数
RatedPlayer::RatedPlayer(unsigned int r, const string & fn, const string & ln, bool ht)
:TableTennisPlayer(fn,ln,ht)
{
this->rating = r;
}
其中TableTennisPlayer(fn,ln,ht)是成员初始化列表,它是可执行的代码,调用TableTennisPlayer构造函数。例如,程序中包含以下声明
RatedPlayer rplayerrl(1140,"Mallory","Duck",true);
则RatedPlayer 构造函数将把实参”Mallory","Duck",true赋给形参fn,ln,ht,然后将这些参数作为实参传递给TableTennisPlayer(父类)的构造函数,后者将创建一个嵌套TableTennisPlayer对象,并将数据“Mallory","Duck",true存储在该对象中。然后,程序进入RatedPlayer(子类)构造函数体,完成RatedPlayer 对象的创建,并将参数r的值赋为rating成员。可以参考下图。
- 将参数传递给基类构造函数
继承和构造函数语法造成的一个bug的更多相关文章
- 从零开始学C++之继承(二):继承与构造函数、派生类到基类的转换
一.不能自动继承的成员函数 构造函数 析构函数 =运算符 二.继承与构造函数 基类的构造函数不被继承,派生类中需要声明自己的构造函数. 声明构造函数时,只需要对本类中新增成员进行初始化,对继承来的基类 ...
- 抓到 Netty 一个 Bug,顺带来透彻地聊一下 Netty 是如何高效接收网络连接的
本系列Netty源码解析文章基于 4.1.56.Final版本 对于一个高性能网络通讯框架来说,最最重要也是最核心的工作就是如何高效的接收客户端连接,这就好比我们开了一个饭店,那么迎接客人就是饭店最重 ...
- 标准模板库(STL)的一个 bug
今天敲代码的时候遇到 STL 的一个 bug,与 C++ 的类中的 const 成员变量有关.什么,明明提供了默认的构造函数和复制构造函数,竟然还要类提供赋值运算符重载.怎么会这样? 测试代码 Tes ...
- 医生加号页改版,就一个Bug, 看医生工作台一期需求
8/8日报 分级埋点: [MobClick event:UmengPagePlusDoctor attributes:@{@"page":@"plusPage&q ...
- 三、Java基础---------关于继承、构造函数、静态代码块执行顺序示例讲解
在上节博客中曾提到过类的继承,这篇文章主要是介绍类的继承.构造函数以及静态代码块的执行顺序. 首先接着分析在黑马基础测试中的一个关于继承的题目,题目描述如下: 声明类Person,包含2个成员变量:n ...
- 从修复 testerhome(rubychina)网站的一个 bug 学习 ruby&rails on ruby
前言 testerhome: http://testerhome.com/topics/1480 对于一个差点脱离前沿技术人,想要学习ruby,就意味着要放弃熟悉的操作系统windows,熟悉的ide ...
- C++菱形继承的构造函数
网上搜了很多,大多是关于菱形虚继承的构造函数应该怎么写,或者就是最简单的,四个类都不带参数的构造函数. 本文旨在记录一下困扰了博主1h的问题,非常浅显,有帮助固然好,如果侮辱谁的智商还见谅,当然无限欢 ...
- [android开发IDE]adt-bundle-windows-x86的一个bug:无法解析.rs文件--------rs_core.rsh file not found
google的android自带的apps写的是相当牛逼的,将其导入到eclipse中方便我们学习扩展.可惜关于导入的资料太少了,尤其是4.1之后的gallery和camera合二为一了.之前导4.0 ...
- JS继承,原型继承,构造函数的继承,非构造函数"的继承
a.原型继承 一.new运算符的缺点 用构造函数生成实例对象,有一个缺点,那就是无法共享属性和方法.比如,在DOG对象的构造函数中,设置一个实例对象的共有属性species. function DOG ...
随机推荐
- Spring Cloud架构教程 (六)消息驱动的微服务【Dalston版】
Spring Cloud Stream是一个用来为微服务应用构建消息驱动能力的框架.它可以基于Spring Boot来创建独立的.可用于生产的Spring应用程序.它通过使用Spring Integr ...
- Quadratic equation
Quadratic equation 牛客多校九B 给定 $(x+y)\%mod=b$ $(x*y)\%mod=c$ 求 $x,y$ 二次剩余 求$((x-y)^{2})\%mod = (b\time ...
- 电脑配置Java环境变量之后,在cmd中仍然无法识别
在电脑上配置了Java的环境变量,但是在cmd框中仍然无法识别: 解决方法:cmd.exe右键---以管理员身份运行,即可识别
- git使用,Git的skil-map,git配置http/https/socks5代理
. 检出.克隆库: git clone git://git.openwrt.org/openwrt.git 2. git查看某个文件的修改历史 git log --pretty=oneline 文件名 ...
- Stream 源码分析
Stream 支持顺序和并行聚合操作的一组元素序列. 1)operations:支持在单个元素上执行的操作,流操作分为中间操作和终止操作 1-1)中间操作: 1-1-1)无状态:unordered() ...
- flex embed 使用
Flex 软件中经常需要使用一些外部的资源,如图片.声音.SWF或字体,虽然你也可以在软件运行的时候引入和载入,但是也可能经常需要直接将这些资源编译(Compile)到软件中,也就是直接嵌入资源(Em ...
- Vultr CentOS下后台跑node
在Mac或者Windows下简直易如反掌.几行命令搞定的事情,但因为使用的是远程SSH连接纯命令行处理,所以需要记录下来怎么弄. 比如, 1. 怎么在什么都没有的CentOS里下载Node安装包? 2 ...
- 《图解设计模式》读书笔记7-1 facade模式
目录 1. Facade模式简介 2. 示例程序 2.1 类图 2.2 程序 3.角色和类图 4.思路拓展 1. Facade模式简介 开发程序的过程中,随着时间的推移,类会越来越多,调用关系会越来越 ...
- APlayer 媒体播放引擎
APlayer媒体播放引擎 Windows平台的播放内核 封闭式 DirectShow 架构,不受系统解码环境干扰 全媒体文件格式支持 丰富的媒体文件传输协议(http/https/ftp/mms/r ...
- SSM Maven MallDemo项目为例
一.创建maven项目 项目结构 创建一个空项目 1. mall (**pom**) 父模块,用于放置公共属性.依赖关系等. 2. mall-util (**jar**) 工具模块,用于放置常用工具类 ...