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

类和柏拉图的理念世界

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

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

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)

{

}

时间: 2024-10-28 02:58:33

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

C#与Java对比学习:类型判断、类与接口继承、代码规范与编码习惯、常量定义(转载)

C#与Java对比学习:类型判断.类与接口继承.代码规范与编码习惯.常量定义 类型判断符号: C#:object a;  if(a is int) { }  用 is 符号判断 Java:object a; if(a instanceof Integer) { } 用 instanceof 符号判断 类与接口的继承: C#:public class MDataRow : List<MDataCell>, IDataRecord, ICustomTypeDescriptor Java:publi

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

Java类中初试化的顺序: 由此得出Java普通类初始化顺序结论: 静态变量 静态初始化块 变量 初始化块 构造器 由此得出Java继承类初始化顺序结论: 1 .继承体系的所有静态成员初始化(先父类,后子类) 2 .父类初始化完成(普通成员的初始化-->构造函数的调用) 3 .子类初始化(普通成员-->构造函数) Java初始化顺序如图: 代码演示: class Sample { Sample(String s) { System.out.println(s); } Sample() { Sy

[转] Java程序员学C#基本语法两个小时搞定(对比学习)

Java程序员学C#基本语法两个小时搞定(对比学习) 对于学习一门新的语言,关键是学习新语言和以前掌握的语言的区别,但是也不要让以前语言的东西,固定了自己的思维模式,多看一下新的语言的编程思想. 1.引包 using System;java用import2.构造函数和java语法相同3.析构函数  变量和类的对象都有生命周期,生命周期结束,这些变量和对象就要被撤销.  类的对象被撤销时,将自动调用析构函数.一些善后工作可放在析构函数中完成.  析构函数的名字为~类名,无返回类型,也无参数.Per

Java程序员学C#基本语法两个小时搞定(对比学习)

对于学习一门新的语言,关键是学习新语言和以前掌握的语言的区别,但是也不要让以前语言的东西,固定了自己的思维模式,多看一下新的语言的编程思想. 1.引包 using System;java用import2.构造函数和java语法相同3.析构函数  变量和类的对象都有生命周期,生命周期结束,这些变量和对象就要被撤销.  类的对象被撤销时,将自动调用析构函数.一些善后工作可放在析构函数中完成.  析构函数的名字为~类名,无返回类型,也无参数.Person类的析构函数为~ Person().  C#中类

深度学习——MSRA初始化

本次简单介绍一下MSRA初始化方法,方法同样来自于何凯明paper <Delving Deep into Rectifiers:Surpassing Human-Level Performance on ImageNet Classification>. Motivation MSRA初始化 推导证明 补充说明 Motivation 网络初始化是一件很重要的事情.但是,传统的固定方差的高斯分布初始化,在网络变深的时候使得模型很难收敛.此外,VGG团队是这样处理初始化的问题的:他们首先训练了一个

对比学习UIKit和AppKit -- ViewController

在iOS中ViewController的基类是UIViewController:Mac中ViewController的基类是NSViewController. Mac中ViewController父类是NSViewController,子类很少,笔者就查到了NSPageController.如果应用中需要,可以Customize. iOS中有好多个ViewController,在Ref2中有介绍,其父类是UIViewController,子类包括UINavigationController.UI

struts2源码学习之初始化(三)

在上一篇struts2源码学习之初始化(二)中已经详细介绍了Dispatcher的初始化工作,只差最后一点,容器的创建.这一篇就仔细介绍容器的创建过程,初始化过程以及容器的作用.还是先从源码入手,上一篇已经分析到了Dispatcher类的init()的这段代码: Container container = init_PreloadConfiguration(); container.inject(this); init_CheckWebLogicWorkaround(container); 接着

对比学习UIKit和AppKit--入门级

UIKit是用来开发iOS的应用的,AppKit是用来开发Mac应用的,在使用过程中他们很相似,可是又有很多不同之处,通过对比分析它们的几个核心对象,可以避免混淆. UIKit和AppKit都有一个Application类,每个应用都只创建一个Application对象,分别是UIAplication和NSApplication的实例.但是创建这个对象的方式还是稍有不同,看iOS应用的main函数: ? 1 2 3 4 5 6 int main(int argc, char * argv[])

深入浅出MongoDB(五)mongo语法和mysql语法对比学习

我们总是在对比中看到自己的优点和缺点,对于mongodb来说也是一样,对比学习让我们尽快的掌握关于mongodb的基础知识. mongodb与mysql命令对比 关系型数据库一般是由数据库(database).表(table).记录(record)三个层次概念组成.而非关系型数据库mongodb是由数据库(database).集合(collection).文档对象(document)三个层次组成.mongodb对于关系型数据库里的表,没有行和列的关系概念,这体现了模式的自由特点. 语法命令如下列