C++_派生类的构造函数及派生类和基类之间的特殊关系
派生类和基类的概念及派生类构造函数的原理:
创建一个叫做TableTennisPlayer的基类,记录会员的名字和是否有球桌。
//声明一个基类
class TableTennisPlayer
{
private:
string firstname;
string lastname;
bool hasTable; public:
TableTennisPlayer();
void Name() const;
bool HasTable() const {return hasTable;};
void ResetTable(bool v) {hasTable =v;};
} //构造函数的定义
TableTennisPlayer::TableTennisPlayer(const string & fn,const string & ln ,bool ht):firstname(fn),lastname(ln),hasTable(ht) {} //Name函数的定义
void TableTennisPlayer::Name() cosnt
{
std::cout << lastname << ", "<<firstname;
}
接下来声明一个派生类:
//声明一个派生类,多了个排名的数据成员
class RatedPlayer: public TableTennisPlayer
{
private:
unsigned int rating;
public:
RatedPlayer(unsigned int r =,const string & fn = "none",const string & ln ="none", bool ht = false);
RatedPlayer(unsigned r, const TableTennisPlayer & tp);
unsigned int Rating() const {return rating;}
void ResetRating (unsigned int r) {rating = r;}
}; //构造函数的实现
RatedPlayer(unsigned int r, const string & fn, const string & ln, bool ht):TableTennisPlayer(fn,ln,ht)
{
rating =r;
} RatedPlayer(unsigned r, const TableTennisPlayer & tp):TableTennisPlayer(tp),rating(r)
{
}
派生类不能访问基类的私有成员,而必须通过基类方法进行访问。
因此派生类构造函数必须使用基类构造函数;
创建派生类对象时,程序首先创建基类对象。从概念上讲,这意味着基类对象应当在程序进入派生类构造函数之前被创建。->C++使用成员初始化列表来完成这种工作。
RatedPlayer::RatedPlayer(unsigned int r, const string & fn, const string & ln, bool ht):TableTennisPlayer(fn,ln,ht)
{
rating = r;
}
如果省略了基类构造函数的话:
RatedPlayer::RatedPlayer(unsigned int r, const string & fn, const string & ln, bool ht)
{
rating = r;
}
首先还是创建基类对象,如果不调用基类构造函数,程序将使用默认的基类构造函数。
因此上述代码与下面等效:
RatedPlayer::RatedPlayer(unsigned int r, const string & fn, const string & ln, bool ht):TableTennisPlayer()
{
rating = r;
}
除非要使用默认构造函数,否则应该显式调用正确的基类构造函数。
还有一种构造函数代码:
RatedPlayer::RatedPlayer(unsigned int r, const TableTennisPlayer & tp):TableTennisPlayer(tp)
{
rating = r;
}
这里也是将TableTennisPlayer的信息传递给了TableTennisPlayer构造函数。
这种方式将调用基类的复制构造函数,如果基类没有定义复制构造函数,但又要使用它,则编译器将自动生成一个。
甚至还可以对派生类成员使用成员初始化列表语法:
RatedPlayer::RatedPlayer(unsigned int r, const TableTennisPlayer & tp):TableTennisPlayer(tp),rating(r)
{
}
派生类构造函数的要点总结:
首先创建基类对象;
派生类构造函数应通过成员初始化列表(TableTennisPlayer(tp))将基类信息传递给基类构造函数;
派生类构造函数应初始化派生类新增的数据成员(rating = r)。
如果没有提供显示构造函数,将使用隐式构造函数。
理解派生类对象创建过程的对象创建顺序:先创建基类对象,在创建派生类对象;
释放对象的顺序与创建对象的顺序相反:首先执行派生类的析构函数,然后自动调用基类的析构函数。
成员初始化列表:(TableTennisPlayer(tp))
派生类构造函数可以使用初始化器列表机制将值传递给基类构造函数。
derived :: derived(type1 x, type2 y) : base(x,y)
{
...
}
Derived是派生类,base是基类。X和Y是基类构造函数使用的变量。
如果派生类构造函数接收到参数10和12,这种机制将把10和12传递给定义为接受这些类型的参数的基类构造函数。类只能将值传递回相邻的基类。虚基类除外,虚基类可以使用相同的机制将信息传递给相邻的基类,以此类推。如果没有在成员初始化列表中提供基类构造函数,程序将使用默认的积累构造函数。成员初始化列表只能用于构造函数。
派生类和基类的关系:(引用、指针)
派生类可以使用基类的方法,条件是方法不是私有的。
基类指针可以再不进行显式类型转换的情况下指向派生类对象。
基类引用可以再不进行显式类型转换的情况下引用派生类对象。
但是基类指针和引用只能调用基类的方法。
C++中要求引用和指针类型与赋予的类型匹配,但这一规则对继承来说是例外。这例外是单向的,也就是说不能将基类对象和地址赋给派生类引用和指针。
但是这种关系是单向的,不能将基类对象和地址赋给派生类引用和指针。
这样要求是有道理的:如果允许基类引用隐式地调用派生类方法,则可以使用基类引用为派生类对象调用基类的方法。因为派生类继承了基类的方法,所以这样做不会有问题。
如果可以将基类对象赋给派生类引用,将发生什么情况?派生类引用能够为基类对象调用派生类方法,这是没有意义的。例如TableTennisPlayer没有rating成员。
用一个图总结如下:

基类引用和指针可以指向派生类对象,将出现一些很有意思的现象:
第一个例子
Show函数如下:
void Show(const TableTennisPlayer & rt)
{
using std::cout;
cout << "Name:";
rt.name();
cout << "\nTable:";
if(rt.HasTable())
cout<<"yes\n";
else
cout <<"no\n";
}
参数rt是一个基类引用,它可以指向基类对象或派生类对象,所以可以在Show()中使用TableTennisPlayer参数或Ratedplayer参数。
 TableTennisPlayer player1("Tara","Boomdea",false);
 RatedPlayer rplayer1(,"Mallory","Duck",true);
 Show(player1);
 Show(rplayer1);
对于形参为指向基类的指针的函数,也存在相似的关系。
总结来说:形参是指向基类引用的函数,可以传基类实参,也可以传派生类实参。
第二个例子(派生类对象可以对基类对象进行初始化)
RatedPlayer olaf1(1840,"Olaf","Loaf",true);
TabelTennisPlayer olaf2(olaf1);
第二行如何初始化?类定义中隐式复制构造函数:
TableTennisPlayer(const TableTennisPlayer &);
这个构造函数的形参是基类引用。因此它可以指向派生类对象。也就是说要将olaf2初始化为olaf1时,将要调用该构造函数,它复制了olaf1的firstname、lastname和hasTable成员。换句话说,它将olaf2初始化为嵌套在RatedPlayer对象olaf1中的TableTennisPlayer对象。
还可以将派生对象赋值给基类对象
RatedPlayer olaf1(1840,"Olaf","Loaf",true);
TableTennisPlayer winner;
winner = olaf1;
这种情况下程序将使用隐式重载赋值运算符;
TableTennisPlayer & operator=(cosnt TableTennisPlayer &) const;
可以看出基类引用指向的也是派生类对象,因此可以将olaf1的基类部分复制给winner。
C++_派生类的构造函数及派生类和基类之间的特殊关系的更多相关文章
- C++的派生类构造函数是否要带上基类构造函数
		//public:Student(int s_age):People(s_age) //C++的派生类构造函数后面是否带上基类构造函数,取决于基类构造函数是否需要传入参数,如果要参数,就一定带上:不需 ... 
- C++学习之路—继承与派生(三):多重继承与虚基类
		(根据<C++程序设计>(谭浩强)整理,整理者:华科小涛,@http://www.cnblogs.com/hust-ghtao转载请注明) 多重继承是指一个派生类有两个或多个基类.例如,有 ... 
- c++ 的类 和 类继承, 什么是c++中的基类和派生类?
		闲云潭影日悠悠,物换星移几度秋 你既然已经做出了选择, 又何必去问为什么选择.鬼谷绝学的要义, 从来都不是回答, 而是抉与择 普通类 #ifndef TABTENN0_H_ #define TABTE ... 
- 派生类地址比基类地址少4(子类与基类指针强行转换的时候,值居然会发生变化,不知道Delphi BCB是不是也这样) good
		大家对虚表并不陌生,都知道每个含有虚函数的类对象都有1个虚指针,但是在现实使用中,却总是因为这而调试半天,才发现原来是虚指针惹的祸.我这几天在调试代码时候也中招了,我的问题是这样的,如下图,CTree ... 
- java基础/一个类A继承了类B,那么A就叫做B的派生类或子类,B就叫基类或超类。
		类重复,pulic class demo1 和class demo1 重复 无主类, 在cmd中输入命令: SET CLASSPATH=. (等号后为英文点符号),即可设置解释的路径为当前路径. 再次 ... 
- 读书笔记_Effective_C++_条款四十三:学习处理模板化基类的名称
		背景是这样的,有两个不同的公司,然后想设计一个MessageSender,为这两个公司发送不同的消息,既支持明文发送SendClearText,也支持密文发送SendEncryptedText.一种思 ... 
- Android--将实体类转化成Json和Map的基类
		package com.newair.talk.base; import android.text.TextUtils; import com.google.gson.Gson; import jav ... 
- C#中派生类调用基类构造函数用法分析
		这里的默认构造函数是指在没有编写构造函数的情况下系统默认的无参构造函数 1.当基类中没有自己编写构造函数时,派生类默认的调用基类的默认构造函数例如: ? 1 2 3 4 5 6 7 8 9 10 11 ... 
- 转 关于C#中派生类调用基类构造函数的理解
		关于C#中派生类调用基类构造函数的理解 .c#class 本文中的默认构造函数是指在没有编写构造函数的情况下系统默认的无参构造函数 1. 当基类中没有自己编写构造函数时,派生类默认的调用 ... 
随机推荐
- LAMP  3.5 mysql备份与恢复
			备份库的命令 mysqldump -uroot -pwangshaojun discuz > /data/discuz.sql 指定用户密码,重定向到某文件 恢复 mysql -uroot -p ... 
- spring各版本下载地址
			发现从spring.io里面找下载连接不好找了,但是机智的我还是找到了,这里做下分享 一.纯spring http://repo.spring.io/release/org/springframewo ... 
- linux动态内核模块编程-3
			将一组与模块相关的命令加载进内核 完成功能类似2,打印proc下的相关信息.但是不用重新编译内核,节省时间,更为灵活 内核模块介绍 模块是在内核空间运行的程序,实际上是一种目标文件,不能单独运行但其代 ... 
- python爬虫实战(3)--图片下载器
			本篇目标 1.输入关键字能够根据关键字爬取百度图片 2.能够将图片保存到本地文件夹 1.URL的格式 进入百度图片搜索apple,这时显示的是瀑布流版本,我们选择传统翻页版本进行爬取.可以看到网址为: ... 
- js实现导航栏的吸顶操作
			<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"% ... 
- 【总结整理】WMS、WMTS、WFS
			参考:http://www.cnblogs.com/naaoveGIS/p/5508882.html WMTS:WMTS是OGC制定的一种发布瓦块地图的Web服务规范,wms主要是动态地图,wmts是 ... 
- Blender 软件 四视图布局的创建方法
			Blender 软件 四视图布局的创建方法 我使用的Blender版本:Blender V 2.77 Q: 为什么要创建一个:四视图布局场景? A: 原因1:四视图布局最适合模型建模.原因2:在 Bl ... 
- MinGW lapack 在windows 上安装
			MinGW基本的配置环境 编译安装 方案一:MinGW Makefiles 我的配置好之后mingw文件夹下没有mingw32-make.exe,使用 mingw-get install mingw3 ... 
- Luogu 2737 [USACO4.1]麦香牛块Beef McNuggets
			NOIP2017 D1T1 的结论,两个数$a, b$所不能表示出的最大的数为$a * b - a - b$. 听了好几遍证明我还是不会 注意到本题中给出的数都非常小,所以最大不能表示出的数$\leq ... 
- 自己实现 String 类
			实现Stirng类:构造函数.复制构造.拷贝构造.重载<<符号(友元) #include <iostream> #include <string.h> #inclu ... 
