C++与C#对比学习:类初始化

时间:2021-07-22 09:23:49

类和柏拉图的理念世界

我们知道面向对象编程中到处是一个个的类,但类只是个概念性的东西,不是个实体,不占内存,你没实例化之前也不能用它.只有把类实例化成一个对象后,它才是一个真正存在的实体.占有内存,能被我们使用.类就有点像柏拉图所说的理念世界一样,柏拉图认为存在着两个世界,一个是我们生活于其中的现实世界,与之对立的是理念世界,理念世界有些啥东东呢?那是个永恒不变的世界,由一堆堆的理念组成,比如人,马,鸟....理念的人只是个概念,不是任何实际的人.而我们现实世界是根据理念世界模拟出来实际的一个个的人,一匹匹的马.有些人可能模拟的比较漂亮,于是就有帅哥美女嘛,有些人就是失败品,于是啥恐龙青蛙的也数量众多.至于模拟的动作谁做的呢?柏拉图没说.有人就认为就是上帝在干这活.

那我们实例化一个类时就有点像上帝干的活,从理念世界拿个空的理念来,然后用个啥构造函数实例化成一个个的对象.

C#类初始化

我们实例化类时一般是用个new关键字比如MyClass arwen = new MyClass().这和C++中的蛮类似.C++这可以这样实例化类表示在heap中开辟一块内存来保存一个对象.用完了之后自己去释放内存.但也可以直接这样MyClass weiwen; 表示是在stack中保存对象,但stack的分配和收回由系统控制. C#则只能用new在heap中开辟内存这一个选择,而且heap中的内存由CRL去管理,用完了它给你去释放,所以此处的heap叫托管堆.

实例化类时我们只是简单的用了个new,但实际上后台还做了其他很多操作.具体做了些啥呢?按顺序做了如下事情

1.初始化类中静态变量

2.调用类中静态构造函数

3.初始化类中非静态变量

4.初始化父类中静态变量

5.调用父类静态构造函数

6.初始化父类非静态变量

7.调用父类构造函数

8.调用自己的构造函数

当然如果没有继承某个父类就不用管父类的事了.如果父类还继承了某个父类,那父类继承重复上面的操作.举个简单的例子看下吧.假如有父类Father,子类Son

class Father

{

public static int age;              //4.赋值为0

public string name;                //6.赋值为null

public Father()                      //7.调用此构造函数

{

Console.WriteLine("I am a lazy father construtor,don't do anything.");

}

public Father(string myName)

{

Console.WriteLine("I am a diligent father constructor.");

name = myName;

}

static Father()              //5.赋值age为110

{

age = 110;

Console.WriteLine("Father static construtor will never do anyting after setting age with a value 110.");

}

}

class Son : Father

{

public static int age;                              //1.初始化age为0

public string name;                               //3.初始化为null

public Son()

{

Console.WriteLine("I am a lazy son construtor,don't do anything.");

}

public Son(string myName)                   //8.调用此构造函数

{

Console.WriteLine("I am a diligent son construtor.");

name = myName;

}

static Son()                         //2.赋值age为11

{

age = 11;

Console.WriteLine("Son static construtor will never do anyting after setting age with a value 11.");

}

}

我们实例化类Son.

Son arwen = new Son("arwen");

输出的结果为

Son static construtor will never do anyting after setting age with a value 11        //类静态构造函数

Father static construtor will never do anyting after setting age with a value 110.   //父类静态构造函数

I am a lazy father construtor,don't do anything.   //父类构造函数

I am a diligent son construtor    //类构造函数

执行顺序都是按那8步来的.不过里面有些要注意的地方.

1.)静态构造的定义只能是static 加类名,不能有参数,不能有public等任何修饰符.在里面只能给静态变量赋值,不能给一般字段赋值,静态构造函数只在类第一次实例化时调用一次.以后再实例化类时不调用.它只能是被默认调用,不能显示调用.除了类第一次实例化时会被调用,第一次使用类中的静态变量前也会被调用.比如你不实例化类Son,而是直接调用

Console.WriteLine(Son.age); 打印结果为

Son static construtor will never do anyting after setting age with a value 11

11

另外虽然const类型的字段也默认是static的.但如果你调用const字段时静态构造函数还是不会执行.

2.)如果类中有很多个构造函数,不管你用哪一个来实例化类,调用父类的构造函数时只会调用无参数的那个.所以如果你没有无参的构造函数,而且有带参的构造函数,而你又作为某个类的父类.那编译时会出错的.如果你啥构造函数都没的话反而没问题.因为如果你任何构造函数都没有,系统会为你默认生成一个.但你如果自己写了任何构造函数带参的或不带参的,系统就不为你默认生成了.

3.)如果想调用父类的有参构造函数必须指定.用关键字base.比如在Son中调用有参构造函数时还要同时调用父类的有参构造函数就像下面这样

public Son(string myName)   :base(myName)

{

Console.WriteLine("I am a diligent son construtor.");

name = myName;

}

这样的话就不会调用父类的无参构造函数了.而有调用有参的那个.不过尽管你这会没调用无参构造函数.但你也不能省了它.无参构造函数必须得写好放那.

4.)我们知道如果子类中有和父类同名的函数的话就会隐藏父类的函数.其实有同名的字段也一样会隐藏.像我举的例子中就有.编译时会有警告,会提醒你加个new关键字.

new public static int age;

new public string name;

改成上面这样就不会有警告.不过看着挺怪的啊.实际上不加new效果也一样的.默认是加了new,只不过显式的再加下new好点吧.

C++类初始化

C++中没有静态构造函数了.调用构造函数的顺序和方式跟C#一样的.只有调用父类的构造函数时有一点点写法上的不一样.把C#中的base换成父类的类名.

另外C++的static变量成员和C#的用法是不一样的.实例化类时也不会默认给初始化.必须自己在类外面去初始化.在C++中的成员变量除了const static类型的可以在声明时同时赋值,其他的都不行.

class Father

{

public:

static int age;

string name;

Father()

{

cout<<"I am a lazy father constructor,don't do anything."<<endl;

}

Father(string myName)

{

cout<<"I am a diligent father constructor."<<endl;

name = myName;

}

};

class Son :public Father

{

public:

static int age;

string name;

Son()

{

cout<<"I am a lazy son constructor,don't do anything."<<endl;

}

Son(string myName):Father(myName)

{

cout<<"I am a diligent son constructor."<<endl;

name = myName;

}

};

int Son::age = 110;     //只能在类外面这样去初始化static变量.前面还得加个int,不过不用加static,也不能再加static.

这样初始化完了你在其他地方就可以Son:age这样去引用了,并且可以直接改变它的值.比如Son::age = 911;

C#与C++初始化对比

从上面我们可以看出,两者构造函数的用法基本上差不多.只不过C++没有静态构造函数.另外调用父类有参构造函时不用base关键字而直接用父类名.

两者的主要区别是在初始化类中成员上.

1.)C++初始化时只要负责根据类中的类型来分配多少内存,没有对成员变量做任何初始化赋值.而且static变量所在占的内存不算在类里面.static变量是保存在静态内存区.而且实例化类时实际还没有给static变量分配内存.只有你在类外面初始化时才会分配内存.

2.)另外你如果在类中定义了一个普通public成员变量,你没有给赋值时用cout打印会发现有一个值.不过那值不确定,而且可能是个蛮大的值.咋回事呢?

实际上我们申请来一块内存,它不是空白的.里面有内容的.比如你用new申请一块内存,然后delete,不是说把内存清空,里面啥都没有了.实际上只是告诉系统这块内存我不要了.然后其他谁申请到这块内存,里面还有你的内容在.只有在它重新赋值后才能擦除掉你的内容.

没初始化成员变量前就使用它自然很危险.所以一定要初始化,C++中这重要的工作就留给构造函数了啊,而C#由于默认给初始化,构造函数就没显得像C++那么重要.

补充

static变量在C#,C++中含义差不多.不过const变量就差远了.C#中const变量默认是static.而C++中const变量不是static.它其实有点像C#中的readonly. const成员变量只能在构造函数中赋值.而且只能在初始化参数列表中赋值.假如类Son中有有成员变量const int no.则只能这样赋值

Son() : no(120)

{

}

C++与C#对比学习:类初始化的更多相关文章

  1. Android(java)学习笔记136:Java类初始化顺序

    Java类中初试化的顺序: 由此得出Java普通类初始化顺序结论: 静态变量 静态初始化块 变量 初始化块 构造器 由此得出Java继承类初始化顺序结论:     1 .继承体系的所有静态成员初始化( ...

  2. Android(java)学习笔记78:Java类初始化顺序

    1. Java类中初试化的顺序: 由此得出Java普通类初始化顺序结论: (1)静态变量 (2)静态初始化块 (3)变量 (4)初始化块 (5)构造器 由此得出Java继承类初始化顺序结论: (1)继 ...

  3. Java程序员学C&num;基本语法两个小时搞定(对比学习)

    对于学习一门新的语言,关键是学习新语言和以前掌握的语言的区别,但是也不要让以前语言的东西,固定了自己的思维模式,多看一下新的语言的编程思想. 1.引包 using System;java用import ...

  4. &lbrack;转&rsqb; Java程序员学C&num;基本语法两个小时搞定(对比学习)

    Java程序员学C#基本语法两个小时搞定(对比学习)   对于学习一门新的语言,关键是学习新语言和以前掌握的语言的区别,但是也不要让以前语言的东西,固定了自己的思维模式,多看一下新的语言的编程思想. ...

  5. MongoDB(五)mongo语法和mysql语法对比学习

    我们总是在对比中看到自己的优点和缺点,对于mongodb来说也是一样,对比学习让我们尽快的掌握关于mongodb的基础知识. mongodb与MySQL命令对比 关系型数据库一般是由数据库(datab ...

  6. struts2源代码学习之初始化(一)

    看struts2源代码已有一段时日,从今天開始,就做一个总结吧. 首先,先看看怎么调试struts2源代码吧,主要是下面步骤: 使用Myeclipse创建一个webproject 导入struts2须 ...

  7. 深入java虚拟机学习 -- 类的加载机制&lpar;续&rpar;

    昨晚写 深入java虚拟机学习 -- 类的加载机制 都到1点半了,由于第二天还要工作,没有将上篇文章中的demo讲解写出来,今天抽时间补上昨晚的例子讲解. 这里我先把昨天的两份代码贴过来,重新看下: ...

  8. 【转】两道面试题,带你解析Java类加载机制&lpar;类初始化方法 和 对象初始化方法&rpar;

    本文转自 https://www.cnblogs.com/chanshuyi/p/the_java_class_load_mechamism.html 关键语句 我们只知道有一个构造方法,但实际上Ja ...

  9. 深入java虚拟机学习 -- 类的卸载

    类的生命周期 在开始本节之前让我们再来回顾下类的生命周期 没看过前6个过程的同学建议从头看下<深入java虚拟机学习 -- 类的加载机制>,这里就不再过多介绍了,着重说下类的卸载 类的卸载 ...

随机推荐

  1. &lbrack;转&rsqb;nopCommerce Widgets and How to Create One

    本文转自:https://dzone.com/articles/what-are-nopcommerce-widgets-and-how-to-create-one A widget is a sta ...

  2. ABP框架理论学习之后台工作&lpar;Jobs&rpar;和后台工作者(Workers)

    返回总目录 本篇目录 介绍 后台工作 后台工作者 让你的应用程序一直运行 介绍 ABP提供了后台工作和后台工作者,它们会在应用程序的后台线程中执行一些任务. 后台工作 后台工作以队列和持续的方式在后台 ...

  3. js实现换肤效果

    一,js换肤的基本原理 基本原理很简单,就是使用 JS 切换对应的 CSS 样式表文件.例如导航网站 Hao123 的右上方就有网页换肤功能.除了切换 CSS 样式表文件之外,通常的网页换肤还需要通过 ...

  4. nyoj 公约数和公倍数

    公约数和公倍数 时间限制:1000 ms  |  内存限制:65535 KB 难度:1   描述 小明被一个问题给难住了,现在需要你帮帮忙.问题是:给出两个正整数,求出它们的最大公约数和最小公倍数. ...

  5. QT 小总结

    遇到的问题: 1:在debug模式下可以顺利执行,但是换到release模式下没法执行了.会显示 exited with code 1 . 解决办法:把产生的release文件放到QT的bin库下,看 ...

  6. spring boot 开发 ajax返回值报错

    org.thymeleaf.exceptions.TemplateInputException: Error resolving template "succeed", templ ...

  7. Qemu编译qemu-system-arm

    /********************************************************************************* * Qemu编译qemu-syst ...

  8. 12 Things Developers Will Love About Oracle Database 12c Release 2

    by Chris Saxon-Oracle It's Here: Oracle Database 12c Release 2 (12.2) Is available on Oracle Cloud. ...

  9. LeetCode 86 ——分隔链表

    1. 题目 2. 解答 从前向后遍历链表,将结点值小于 x 的结点放入到新链表 1 中,将结点值大于等于 x 的结点放入新链表 2 中.最后,将新链表 2 拼接在新链表 1 后面即可. /** * D ...

  10. 前端知识点总结——CSS

    1.CSS的概述 1.什么是CSS? CSS:Cascading Style Sheets层叠样式表,级联样式表(简称:样式表) 2.作用 设置HTML网页元素的样式 3.HTML与CSS的关系 HT ...