当前位置: 首页 > news >正文

C++ VS C#(10):构造函数与析构函数

//=====================================================================
//TITLE:
// C++ VS C#(10):构造函数与析构函数
//AUTHOR:
// norains
//DATE:
// Friday 18-January-2011
//Environment:
// Visual Studio 2010
// Visual Studio 2005
//=====================================================================

1. 构造函数与析构函数

类最不可或缺的是什么?没错,就是构造函数和析构函数。对于C++和C#而言,两者的基础语法是一致的,构造函数都是和类名称同名,而析构函数就是在类名称之前增加~标志,如:
//C++ class CMyBase { public: //构造函数 CMyBase(){}; //析构函数 virtual ~CMyBase(){}; };
//C# class CMyBase   {    //构造函数 public CMyBase(){} //析构函数 public ~CMyBase(){}   };
  
  不过在C#中,虽然我们声明的析构函数是~CMyBase(),但在.NET实际调用的却是Finalize()。说白了,Finalize()其实就是我们声明的析构函数~CMyBase()的别名。那么我们可不可以不定义~CMyBase(),而直接实现Finalize()呢?建议是最好不要。因为~CMyBase()会默认调用基类的析构函数,而Finalize()必须手工调用,存在一定的风险性。
  
  接下来的区别,就更加扩大了两者的区别。默认情况下,派生类调用的是基类的默认构造函数,如果需要调用非默认的构造函数,两种语言都有相应的语法。
  
  首先我们来看看C++,如果需要调用基类的非默认构造函数,那么我们必须要在派生类的构造函数中明确指出,也就是明确调用基类的非默认构造函数,如:
  //C++      //基类   class CMyBase   {   public:    //默认构造函数    CMyBase(){};       //非默认构造函数    CMyBase(int i){};       //析构函数    virtual ~CMyBase(){};   };      //派生类   class CDerive:    public CMyBase   {   public:    //默认构造函数    CDerive(){};       //明确指出调用的是基类的非默认构造函数    CDerive(int i):CMyBase(i){};       //析构函数    virtual ~CDerive(){};   };
  
  C#的手法和C++其实也差不多,不过这里并不需要明确指出基类的构造函数,而是用base关键字替代,如:
  //C#      //基类 class CMyBase   {    //默认构造函数 public CMyBase(){} //非默认构造函数 public CMyBase(int i){} //析构函数 public ~CmyBase(){} }; class CMyDerive: CMyBase   {    //默认构造函数 public CMyDerive(){} //以base关键字来明确指出调用的是基类的非默认构造函数 public CMyDerive(int i): base(i){} //析构函数 public ~ CMyDerive (){}   };   

  C++需要明确指出基类的名称,而C#可以不用理会而直接用base替代,相对来说,似乎C#更为简便一些。因为如果基类的名称有所改变的话,那么C#只需要修改继承时的名字,而C++需要修改的似乎更多。那么为什么C++为什么不能也增加一个类似于base的关键字呢?这个和继承的机制有关。因为C#只支持单继承,也就是只能允许有一个基类,所以base关键字指向非常明确;而C++因为是能够多重继承的,也就是说有多个基类,单单的一个base关键字根本无法明确指出是哪个基类。
  
  
  除了base关键字以外,C#还支持一个this关键字。和base指向基类的不同,this指向的是当前类。简单点来说,.NET在执行当前的类构造函数之前,会先执行this指向的当前类的构造函数。当然咯,this的执行次序还是在基类的构造函数完毕之后。我们来看看下面这段代码:
class CMyBase   {    //默认构造函数 public CMyBase() { Console.WriteLine("CMyBase()"); } //非默认构造函数 public CMyBase(int i) { Console.WriteLine("CMyBase(i)"); } }; class CMyDerive: CMyBase   {    //默认构造函数 public CMyDerive() { Console.WriteLine("CMyDerive()"); } //因为这里有this关键字,所以会先调用CMyDerive()函数,再调用该函数 public CMyDerive(int i) : this() { Console.WriteLine("CMyDerive(int i)"); }   };      

  如果你是以CMyDerive derive1 = new CMyDerive()的形式来定义一个对象,那么输出信息如下:
  CMyBase()
  CMyDerive()

  
  而如果是以CMyDerive derive2 = new CMyDerive(1)来定义,那么输出信息如下:
  CMyBase()
  CMyDerive()
  CMyDerive(int i)

  
  从输出信息可以很明确的看出,因为在CMyDerive(int i)构造函数中用this()指定了另外一个构造函数,也就是代码中的CMyDerive(),所以执行时就先调用了CMyDerive(),最后再是CMyDerive(int i)。
  
  回到C++,有什么办法也能实现类似的功能呢?能不能像调用基类的构造函数那样,直接在构造列表中用本派生类的名字来调用别的构造函数呢?也就是说,代码能不能这样:
  class CDerive:    public CMyBase   {   public:    CDerive(){};    //采用本派生类的名字来调用别的构造函数,但很可惜,无法编译通过   CDerive(int i):CDerive(){};   };
  
  很可惜,在我的vs2005中会报错:error C2614: 'CDerive' : illegal member initialization: 'CDerive' is not a base or member。
  
  如果真的需要实现C#的this关键字的功能,那么我们只能在代码域中直接调用,如下所示:
  class CDerive:    public CMyBase   {   public:    CDerive(){};    CDerive(int i)    {    //直接调用别的构造函数    CDerive();    };   };

相关文章:

  • oracle 10g OEM常规错误解决
  • Hibernate实体关系映射(OneToMany单边)——完整实例
  • JavaScript学习笔记(三)——this、原型、javascript面向对象
  • 在Common Lisp中使用 List Comprehension
  • 基础数据结构
  • C++ VS C#(11):结构体和对象的细微区别
  • 数据库被黑后留下的数据
  • 通过html字符串连接组合并调用javascript函数
  • ARM+LINUX移植攻略(十)支持东华 3.5寸LCD输出console信息和BMP图片、logo
  • 字符串截取函数slice, substring, substr
  • ARM+LINUX移植攻略(十二)U-boot-2009.08利用tftp服务下载内核和利用nfs服务挂载nfs文件系统...
  • 快速排序(转)
  • Windows Phone 7 不温不火学习之《Expression Blend 创建渐变效果和创建Storyboard动画》...
  • DelphiXE8FMX工程实现无边框托动(发送消息)
  • Vue 响应式总结
  • 自己简单写的 事件订阅机制
  • [译]CSS 居中(Center)方法大合集
  • 【翻译】babel对TC39装饰器草案的实现
  • 【知识碎片】第三方登录弹窗效果
  • HTTP请求重发
  • in typeof instanceof ===这些运算符有什么作用
  • Java 网络编程(2):UDP 的使用
  • javascript数组去重/查找/插入/删除
  • JS题目及答案整理
  • Lucene解析 - 基本概念
  • Perseus-BERT——业内性能极致优化的BERT训练方案
  • React系列之 Redux 架构模式
  • STAR法则
  • vue-cli3搭建项目
  • 分类模型——Logistics Regression
  • 简单实现一个textarea自适应高度
  • 每天一个设计模式之命令模式
  • 你不可错过的前端面试题(一)
  • 前端攻城师
  • 实现菜单下拉伸展折叠效果demo
  • 我感觉这是史上最牛的防sql注入方法类
  • 详解移动APP与web APP的区别
  • 异常机制详解
  • - 转 Ext2.0 form使用实例
  • ​如何在iOS手机上查看应用日志
  • #1015 : KMP算法
  • (+4)2.2UML建模图
  • (06)金属布线——为半导体注入生命的连接
  • (2/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序
  • (附程序)AD采集中的10种经典软件滤波程序优缺点分析
  • (亲测)设​置​m​y​e​c​l​i​p​s​e​打​开​默​认​工​作​空​间...
  • (十三)Maven插件解析运行机制
  • (算法)Game
  • (五)大数据实战——使用模板虚拟机实现hadoop集群虚拟机克隆及网络相关配置
  • (详细版)Vary: Scaling up the Vision Vocabulary for Large Vision-Language Models
  • .[hudsonL@cock.li].mkp勒索加密数据库完美恢复---惜分飞
  • .bat批处理(十一):替换字符串中包含百分号%的子串
  • .NET 4.0中的泛型协变和反变
  • .ui文件相关
  • /bin/bash^M: bad interpreter: No such file or directory