- 浏览: 261382 次
- 性别:
- 来自: 济南
文章分类
- 全部博客 (303)
- c (31)
- c++ (16)
- java (18)
- c# (1)
- python (3)
- java web (6)
- oracle (7)
- sqlserver (2)
- mysql (2)
- android (24)
- android系统 (15)
- android多媒体部分 (15)
- android游戏 (12)
- linux (26)
- javaScript (1)
- ajax (1)
- node JS (2)
- html (5)
- apache (3)
- jboss (1)
- weblogic (0)
- 通信协议 (10)
- 云计算 (1)
- 分布式 (5)
- ejb (1)
- webservice (5)
- 设计模式 (16)
- JNI (6)
- swing (13)
- 版本控制 (1)
- UML (1)
- xml (4)
- spring (5)
- hibernate (5)
- struts1 (3)
- struts2 (4)
- ibatis (0)
- tomcat (2)
- 心得体会 (1)
- css (1)
- 嵌入式 (41)
- arm体系结构 (10)
虚函数和多态性
使用基类指针,示例代码如下(从Box派生两个类)
class Carton:public Box{
};
class ToughPack:public Box{
};
Carton aCarton(10.0,10.0,5.0);
Box * pBox=& aCarton;
ToughPack hardcase(12.0,8.0,4.0);
pBox=&hardcase;
有如下语句:pBox()->volume; 此时如pBox包含的是Carton的对象地址,那
么它指向的就是Carton对象的函数,同理hardcase也一样
调用继承的函数
头文件Box.h
#ifndef BOX_H
#define BOX_H
================ 基类=========================================
class Box{
//构造器
public:
Box(double lengthValue=1.0,double widthValue=1.0,double
heightValue=1.0);
//成员函数
void showVolume() const;
double volume() const;
//成员变量
protected:
double length;
double width;
double height;
};
#endif
==================================================================
实现文件Box.cpp
#include "Box.h"
#include <iostream>
using std::cout;
using std::endl;
//构造函数
Box::Box(double lvalue,double wvalue,double hvalue):length
(lvalue),width(wvalue),height(hvalue){}
void Box::showVolume() const{
cout<<"Box usable volume is "<<volume()<<endl;
}
double Box::volume() const{
return length*width*height;
}
=================派生类============================================
头文件ToughPack.h
#ifndef TOUGHPACK_H
#define TOUGHPACK_H
#include "Box.h"
class ToughPack:public Box{
public:
ToughPack(double lengthValue,double widthValue,double
heightValue);
double volume() const;
}
===================================================================
实现文件ToughPack.cpp
#include "ToughPack.h"
ToughPack::ToughPack(double lval,double wval,double hval):Box
(lval,wval,hval){}
double ToughPack::volume() const{
return 0.85*length*width*height;
}
====================================================================
使用继承的函数
#include <iostream>
#include "Box.h"
#include "ToughPack.h"
using std::cout;
using std::endl;
int main(){
Box myBox(20.0,30.0,40.0);
ToughPack hardcase(20.0,30.0,40.0);
cout<<endl;
myBox.showVolume();//调用基类函数
hardcase.showVolume();//调用派生类函数
return 0;
}
如果想直接调用ToughPack中的valume()方法,示例代码如下:
cout<<"hardcase volume is"<<hardcase.volume()<<endl;
Box *pBox =&hardcase;
cout<<"hardcase volume through pBox is"<<pBox->volume()<<endl;
虚函数
一个基类中如果定义了虚函数,那么在派生于这个类的任何类,该函数都是动态
绑定的.(virtual) 使用对象的引用或指针都可以调用虚函数
注: 每个派生类都可以执行虚函数的自有版本
示例代码
class Box {
//构造器
public:
Box(double lenthValue=1.0,double widthValue=1.0,double
heightValue=1.0);
void showVolume() const;
//虚函数
virtual double volume() const;
//成员变量
protected:
double length;
double width;
double lenght;
}
=================================================================
Carton.h头文件
#ifndef CARTON_H
#define CARTON_H
#include <string>
#include "Box.h"
using std::string;
class Carton:public Box{
//构造函数
pulbic:
Carton(double lv,double wv,double hv,string
material="Cardboard");
//副本构造成器
Carton(const Carton & aCarton);
//析构函数
double volume() const;
//成员变量
private:
string * pMaterial;
};
#endif
==========================================================
实现文件Carton.cpp
#include "Carton.h"
Carton::Carton(double lv,double wv,double hv,string material):Box
(lv,wv,hv){
pMaterial=new string(material);
}
Carton::Carton(const Carton & aCarton){
length=aCarton.width;
width=aCarton.height;
height=aCarton.width;
pMaterial=new string (* aCarton,pMaterial);
}
Carton::~Carton(){
delete pMaterial;
}
double Carton::volume() const{
double vol-(length-0.5)*(width-0.5)*(height-0.5);
return vol>0.0?vol:0.0;
}
=============================================================
调用访函数的示例代码如下:
#include <iostream>
#include "Box.h"
#include "ToughPack.h"
#include "Carton.h"
using std::cout;
using std::endl;
int main(){
Box myBox(20.0,30.0,40.0);
ToughPack hardcase(20.0,30.0,40.0);
Carton aCarton(20.0,30.0,40.0);
//显示三个对象的体积
cout<<endl;
myBox.showVolume();
hardcase.showVolume();
aCarton.showVolume();
cout<<endl;
pBox=& hardcase;
cout<<"hardcase volume through pBox is"<<pBox->volume()<<endl;
pBox->showVolume();
cout<<endl;
pBox=& aCarton;
cout<<"aCarton volume through pBox is"<<pBox->volume()<<endl;
pBox->showVolume();
return 0;
}
虚函数中的默认参数值
如果在基类的虚函数中使用默认参数,在通过基类指针调用该函数时,只会
使用基类中的默认参数
头文件Box.h
#ifndef BOX_H
#define BOX_H
class Box {
//构造器
public:
Box(double lenthValue=1.0,double widthValue=1.0,double
heightValue=1.0);
void showVolume() const;
//虚函数
virtual double volume(const int i=5) const;
//成员变量
protected:
double length;
double width;
double lenght;
};
#endif
====================================================================
实现文件Box.cpp
#include "Box.h"
#include <iostream>
using std::cout;
using std::endl;
//构造函数
Box::Box(double lvalue,double wvalue,double hvalue):length
(lvalue),width(wvalue),height(hvalue){}
void Box::showVolume() const{
cout<<"Box usable volume is "<<volume()<<endl;
}
//使用默认参数
double Box::volume(const int i) const{
cout<<"Parameter"<<i<<endl;
return length*width*height;
}
====================================================================
派生类 头文件ToughPack.h
#ifndef TOUGHPACK_H
#define TOUGHPACK_H
#include "Box.h"
class ToughPack:public Box{
//构造成器
public:
ToughPack(double lengthValue,double widthValue,double
heightValue);
//虚函数
virtual double volume(const int i=500) const;
};
#endif
===================================================================
实现文件ToughPack.cpp
#include "ToughPack.h"
#include <iostream>
using std::cout;
using std::endl;
ToughPack::ToughPack(double lVal,double wVal,double hVal):Box
(lVal,wVal,hVal){}
double ToughPack::volume() const{
cout<<"Parameter"<<i<<endl;
return 0.85*length*width*height;
}
=====================================================================
调用时
#include <iostream>
#include "Box.h"
#include "ToughPack.h"
#include "Carton.h"
using std::cout;
using std::endl;
int main(){
Box myBox(20.0,30.0,40.0);
ToughPack hardcase(20.0,30.0,40.0);
Carton aCarton(20.0,30.0,40.0);
cout<<endl;
myBox.showVolume();
hardcase.showVolume();
aCarton.showVolume();
cout<<endl;
cout<<"hardcase volume is"<<hardcase.volume()<<endl;
Box pBox=& myBox;
cout<<"myBox volume through pBox is"<<pBox->volume()<<endl;
pBox->showVolume();
cout<<endl;
pBox=& hardcase;
cout<<"hardcase volume through pBox is"<<pBox->volume()<<endl;
pBox->showVolume();
cout<<endl;
pBox=& aCarton;
cout<<"aCarton volume through pBox is"<<pBox->volume()<<endl;
pBox->showVolume();
return 0;
}
通过引用来来调用虚函数
对虚函数的引用
#include <iostream>
#include "Box.h"
#include "ToughPack.h"
#include "Carton.h"
using std::cout;
using std::endl;
void showVolume(const Box & rBox);
int main(){
Box myBox(20.0,30.0,40.0);
ToughPack hardcase(20.0,30.0,40.0);
Carton aCarton(20.0,30.0,40.0);
cout<<endl;
showVolume(myBox);
showVolume(hardcase);
showVolume(aCarton);
return 0;
}
void showVolume(const Box & rBox){
rBox.showVolume();
}
调用虚函数的基类版本 示例代码如下:
通过派生类对像的指针或引用虚函数的派生类版本
Carton aCarton(40.0,30.0,20.0)
Box* pBox=&aCarton;
计算Carton对像的总体积损失:
double difference=pBox->Box::volume()->pBox->volume();
pBox->Box::volume()
在指针和类对像之间的转换
如果程序包含派生类的指针,就可以把指针隐式转换为基类指针,(可以是直接基
类指针,也可以是间接基类指针)
例如:
Carton * pCarton=new Carton(30,40,10);
可以把这个隐式指针转换为Carton的直接基类指针,
Box * pBox=pCarton;
还可以把派生类的隐式指针转换为间接基类的指针,示例化码如下:
CerealPace继承Carton,carton继承Box
Box* pBox=pCerealPack;//把pCerealPack中的地址从“指向CerealPack”的指
针类型转换为"指向Box"的指针类型
如果要指定显示转换,可以使用static_case<>()运算符
Box* pBox=static_case<Box*>(pCerealPack);
动态强制转换 (只能应用于多态类类型的指针和引用,即至少包含一个虚函数的
类类型)
在使用期间,要指定动态强制转换,应使用dynamic_case<>()运算符
动态转换指针
动态制转换有两种类型:
一种是沿着类层次结构向下进行强制转换(从直接或间接基类的指针转换为派
生类型的指针,称为downcast)
示例代码如下:
目标类型 要强制转换为新类型的表达式
Carton * pCarton=dynamic_cast<Carton*> (pBox);
注:Carton和Box必须包含虚函数
另一种是跨类层次的强制转换,称为crosscast
Contents* pContents=dynamic_cast<Contents*>(pBox);
注: Contents和Box类都必须是多态性的
假定一个Box对象指向某个对象,如果想调用Carton类的一个非虚函数
基类指针只允许调用派生类的虚函数,而dynamic_cast<>()运算符可以调用
非虚函数
示例代码:如果想调用Carton类的一个非虚函数在员surface()方法
dynamic_cast<Carton*>(pBox)->surface();
注:这样作的前提是确保pBox指向Carton对象或指向Carton作为基类的对象
正确写法:
if(Carton* pCarton=dynamic_cast<Carton*>(pBox)){
pCarton->surface();
}
注:如果要强制转换的指针类型是const,则目标类型也必须是const,
如果把const指针转换为非const类型指针,就必须使用const_cast<>()
转换引用(函数的引用参数)
示例人代码如下:
double doThat(Box & rBox){
Carton& rCarton=dynamic_cast<Carton&>(rBox);
}
多态性的成本 ( 虚函数的调用需要额外和开销)
简单的说包含相同数据成员,含有虚函数的类要比没有的类占用的内存要多
内存使用多的原因:在创建多态类的对象,要在对象中创建一个特殊指针(用
于调用对象中的虚函数)
纯虚函数(类似于接口-所有的成员都有是抽象成员)
示例代码如下:
class Shape{
public:
virtual void draw() const=0;
virtual void move(const Point& newPosition)=0;
protected:
Point position;
Shape(const Point& shapePosition):position(shapePosition){}
};
抽象类(抽象类的指针或引用可以用作参数或返回类型)
抽象类的构造函数可以在派生类的构造函数的初始化列表中调用(一般为
protected类型)
示例代码:声明一个新类,它把shape类作为基类
class Circle:public Shape{
public :
Circle(Point center,double circleRadius):Shape(),radius
(circleRadius){}
virrual void draw() const{
cout<<"Circle center"<<position<<"radius"<<radius<<endl;
}
virrual void move(const Point& newCenter){
position=newCenter;
}
private:
double radius;
}
注: Circle类定义了draw()和move()函数, 如果没有定义这两个方法中的
任何一个,Circle就是一个构造类
如果类中有一个纯虚函数,该类就是抽象类,派生类必须定义基类中的每
个纯虚函数,否则派生类也是一个抽象类,当然抽象类还可以包含非纯虚函数
示例代码:
class Box{
public:
Box(double lengthValue=1.0,double widthValue=1.0,double
heightValue=1.0);
protected:
double length;
double width;
double height;
};
#include<iostream>
#include "Box.h"
#include "ToughPack.h"
#include "Carton.h"
using std::count;
using std::endl;
int main(){
cout<<endl;
ToughPack hardcase(20.0,30.0,40.0);
Box* pBox=&hardcase;
cout<<"Volume of hardcase is"<<pBox->volume()<<endl;
Carton aCarton(20.0,30.0,40.0);
pBox=&aCarton;
cout<<"volume of aCarton is"<<pBox->volume()<<endl;
return 0;
}
用接口的抽象类 (只有包含一个纯虚接口的抽象类可以用于定义标准类接口)
间接的抽象类
多级继承 示例代码
vessel为Box的基类
头文件如下
#ifndef VESSEL_H
#define VESSEL_H
class Vessel{
public:
virrual double volume() const=0;// 虚函数
};
#endif
Box类的头文件为:
#ifndef BOX_H
#define BOX_H
#include "Vessel.h"
class Box:public Vessel{
public:
Box(double lengthValue=1.0,double widthValue=1.0,double
heightValue=1.0);
virtual double volume() const;//不是纯虚状态
protected:
double length;
double width;
double height;
};
#endif
实现文件Box.cpp
double Box::volume() const{
return length * width* height;
}
另一个vessel中另一个派生类can,头文件can.h
#ifndef CAN_H
#define CAN_H
#inclued "Vessel.h"
class Can:pulbic Vessel{
public :
Can(double canDiameter,double canHeight);
virtual double volume() const;//
protected:
double diameter;
double height;
static const double pi;//虚函数
};
#endif
实现文件can.cpp
#include "Can.h"
Can::Can(double canDiameter,double canHeight):diameter
(canDiameter),height(canHaight){}
double Can:volume() const{
return pi* diameter*diameter*height/4;
}
const double Can::pi=3.1415926;
测试主函数
#include <iostream>
#include "Box.h"
#include "ToughPack.h"
#include "Carton.h"
#include "Can.h"
using std::cout;
using std::endl;
int main(){
//初始化容器
Box aBox(40,30,20);
Can aCan(10,3);
Carton aCarton(40,30,20);
ToughPack hardcase(40,30,20);
Vessel* pVessels[]={&aBox,&aCan,&aCarton,&hardcase};
cout<<endl;
for(int i=0;i<sizeof pVessels/sizeof(pVessels[0]);i++){
cout<<"Volume is"<<pVessels[i]->value<<endl;
}
return 0;
}
通过指针释放对象
示例代码如下:
在vesel类的头文件中添
class Vassel{
public:
virtual double volume() const=0;// 虚函数
~Vessel();//析构函数
}
实现文件中添加如下代码
#include <iostream>
#include "Vessel.h"
Vessel::~Vessel(){
sed::cout<<"Vessel destructor"<<std::endl;
}
在派生类加添加相同的输出一句
测试主函数如下:
#include <iostream>
#include "Box.h"
#include "ToughPack.h"
#include "Carton.h"
#include "Can.h"
using std::cout;
using std::endl;
int main(){
//初始化容器
Box aBox(40,30,20);
Can aCan(10,3);
Carton aCarton(40,30,20);
ToughPack hardcase(40,30,20);
Vessel* pVessels[]={&aBox,&aCan,&aCarton,&hardcase};
cout<<endl;
for(int i=0;i<sizeof pVessels/sizeof(pVessels[0]);i++){
cout<<"Volume is"<<pVessels[i]->value<<endl;
}
//释放资源
for(int i=0;i<sizeof pVessels/sizeof(pVessels[0]);i++){
delete pVessels[i];
}
return 0;
}
结果是几个类在释放资源时都调用基类Vessel destructor的析构函数
虚析构函数
在析构函数声明中添加关键字virtual
调用虚拟析构函数,示例代码如下:
class Vessel{
public :
virtual double volume() const=0;//虚函数
virtual ~vessel();//虚析构函数
};
在运行期间标识类型
检查指针指向类型 (typeid()运算符,需在头文件中包含<typeinfo>
)
if(typeid(* pVessel)==typeid(Carton)){
cout<"Pointer is type Carton"<<endl;
}else{
cout<"Pointer is not type Carton"<<endl;
}
类成员的指针
数据成员指针 它包含类成员的地址,仅在与类对象组合使用时,才指向内
存的某个位置
示例代码如下:
class Box{
public :
Box( Box(double lenthValue=1.0,double
widthValue=1.0,double heightValue=1.0);
void showVolume() const;
public : //原始状态为protected
double length;
double width;
double height;
}
//定义一个指针
double Box::* pData;
//注创建同意词的语名
typedef double Box:: * pBoxMember;//pBoxMember替代double Box::*
//下面的语句把类成员width的地址赋于这个指针
pData=&Box::width;
"成员指针"选择运算符
成员指针总是要和对象、对象的引用或对象的指针一起使用
示例代码如下:
Box myBox(20.0,30.0,40.0);
调用myBox的width成员
myBox.*pData
应用Box指针
Box* pBox=&myBox;
通过指针访问myBox 中的数据成员
pBox->*pData//此处用到间接成员指针->*
使用成员指针,示例代码
#include <iostream>
#include "Box.h"
#include "ToughPack.h"
#include "Carton.h"
using std::cout;
using std::endl;
typedef double Box::* pBoxMember;
int main(){
//初始化三个容器
Box myBox(20.0,30.0,40.0);
ToughPack hardcase(35.0,45.0,55.0);
Carton aCarton(48.0,58.0,68.0);
//使用成员指针,指向成员长度
pBoxMember pData=&Box::length;
cout<<endl;
cout<<"Length member of myBox is"<<myBox.*pData<<endl;
pData=&Box::width;//指向成员宽度
cout<<"width member of myBox is"<<myBox.*pData<<endl;
pData=&Box::height;//指向成员高度
cout<<"height member of myBox is"<<myBox.*pData<<endl;
cout<<"height member of hardcase is"<<hardcase.*pData<<endl;
cout<<"height member of aCarton is"<<aCarton.*pData<<endl;
//利指针访问成员指针中的成员
Box* pBox=&myBox;
cout<<"height memeber myBox is"<<pBox->*pData<<endl;
pBox=&hardcase;
cout<<"height memeber hardcase is"<<pBox->*pData<<endl;
cout<<endl;
return 0;
}
发表评论
-
c++学习笔记十六
2013-05-14 21:50 820c with classes 尽量以const e ... -
c++学习笔记十七
2013-05-18 23:44 874构造、析构、赋值运算 c++会为一个空类声明一个copy构造函 ... -
c++学习笔记一
2012-09-03 15:25 605基本概念 第一个程序 h ... -
c++学习笔记二
2012-09-03 15:26 361处理基本数据类型 1 混合表达式 (向上转型) 2 赋 ... -
c++学习笔记三
2012-09-03 15:26 543选择和决策 比较数据值 1 关系运算符:< &g ... -
c++学习笔记五
2012-09-03 15:27 598while do-while for循环 循环和变 ... -
c++学习笔记六
2012-09-03 15:28 268指针 可以使用指针记 ... -
c++学习笔记七
2012-09-03 15:28 558使用函数编程 程序的分解 1 函数 定义函 ... -
c++学习笔记八
2012-09-03 15:29 595函数 1 函数的重载: 函数名相同,参数个数不同 ... -
c++学习笔记九
2012-09-20 23:14 698程序文件和预处理指令 1 程序文件 头文件:类型定 ... -
c++学习笔记十
2012-09-20 23:18 594创建自已的数据类型 1 对像的概念 2 c++中的结构 ... -
c++学习笔记十一
2012-09-20 23:20 240类 1 封装 继承 多 ... -
c++学习笔记十二
2012-09-20 23:20 689类的操作 1 类对象使用指针的三种情况: ... -
c++学习笔记十三
2012-09-20 23:31 667运算符重载 1 为自已的类实现运算符 运 ... -
c++学习笔记十四
2012-09-20 23:32 603继承 1 类和面向对象编程 2 类的继承 继承 ...
相关推荐
### C++ 学习笔记精华版 #### 一、C++ 语言概述 **1、历史背景** - **C++ 的江湖地位** - Java、C、C++、Python、C# 是当前主流的编程语言之一,而 C++ 在这些语言中以其高效性和灵活性著称。 - **C++ 之父 ...
C++学习笔记C++学习笔记C++学习笔记C++学习笔记C++学习笔记
C++学习笔记
这份"C++学习笔记"涵盖了C++的基础到高级概念,旨在帮助初学者和有一定经验的程序员深入理解并掌握C++。 在C++的学习过程中,以下几个关键知识点是不可或缺的: 1. **基础语法**:C++起源于C语言,因此它保留了...
C++是一种静态类型、编译式、通用的编程语言,它支持过程化编程、面向对象编程和泛型编程。C++广泛应用于软件开发领域,包括操作...以上内容覆盖了C++语言中一些基础知识点,对于学习和理解C++编程具有重要的指导意义。
【C++学习笔记】这份详尽的资源是为那些希望深入了解C++编程语言的人们精心准备的。C++是一种强大的、通用的编程语言,它的设计理念是面向对象,同时支持过程化编程,使得它在系统软件、应用软件、游戏开发、设备...
【C++ 学习笔记】深入理解编程与C++基础 C++是一种强大的、面向对象的编程语言,广泛应用于系统软件、游戏开发、嵌入式系统以及许多高性能应用。学习C++不仅仅是掌握语法,更重要的是理解编程的核心概念,以便更好...
C++ 学习笔记C++ 学习笔记C++ 学习笔记C++ 学习笔记002
C++ 学习笔记C++ 学习笔记C++ 学习笔记C++ 学习笔记C++ 学习笔记003
C++ 学习笔记C++ 学习笔记C++ 学习笔记C++ 学习笔记C++ 学习笔记004
C++ 学习笔记C++ 学习笔记C++ 学习笔记C++ 学习笔记001
【C++学习笔记概述】 C++是一门强大的编程语言,其在C语言的基础上进行了扩展,引入了许多现代化的特性。这份笔记主要涵盖了C++的基础知识,包括C++11和C++17的新特性,旨在帮助初学者理解C++的核心概念。 ### C++...
C++学习笔记 本文档提供了C++语言的基础知识,包括输入输出、变量、数据类型、运算符、内存管理、指针、流程控制语句等。 输入输出 C++语言提供了多种输入输出方式,包括使用cin和cout对象。cin对象用于从标准...
《新手C++学习笔记》是一份专为编程初学者打造的资源,旨在帮助那些刚刚踏入C++编程领域的“菜鸟”快速成长。这份笔记包含了前辈们的实践经验总结,具有很高的学习价值。文档以.doc格式存储,方便读者使用常见的文字...
这份"C++学习笔记"涵盖了C++的基础概念、语法结构、面向对象编程以及可能的高级主题,旨在帮助初学者或者有经验的程序员巩固C++知识。 首先,C++是从C语言发展而来,它保留了C语言的效率,同时引入了类和对象的概念...
C++是一种强大的面向对象编程语言,它源自C语言并扩展了其...学习这些概念是成为C++程序员的第一步。在实际编程中,还需要理解类、对象、继承、多态等面向对象编程的概念,以及函数、模板、文件操作等更高级的主题。
《C++学习笔记经典(与C比较)》这份资料应该会详细讲解这些知识点,并通过实例来帮助读者深入理解C++与C的差异,以及如何在实际编程中应用C++的特性和功能。这份资料可能会涵盖基本语法、类和对象、模板、STL的使用...
"黑马C++学习笔记" 本笔记主要记录了C++的基础知识和一些重要的概念,包括变量的声明、赋值、输出、引用、指针、结构体等。 变量声明和赋值 在C++中,变量的声明和赋值是非常重要的。变量可以是整数、浮点数、...