构造方法

C# 实例化类的执行顺序

♀尐吖头ヾ 提交于 2019-11-27 01:28:54
先进行细分: 类的成员分为:字段、属性、方法、构造方法 成员的修饰符:静态成员、实例成员 层次结构:父类、子类 先不考虑继承关系,执行顺序为: 静态字段 静态构造方法 实例字段 实例构造方法 属性和方法是在调用的时候才执行,这里就不考虑了。如何理解上面的执行过程?假如让我来设计执行过程,我该如何考虑,依据是什么? 首先,静态的东西是大家共享的,也就是相同的。应该先关心共享的东西,再关系个人的东西。“先公后私”,呵呵。 其次,实例化之前,应该先初始化自己的内部数据。 现在考虑继承关系,执行顺序为: 子类的静态字段 子类的静态构造方法 子类的实例字段 父类的静态字段 父类的静态构造方法 父类的实例字段 父类的实例构造方法 子类的实例构造方法 在子类的实例字段和子类的实例构造方法之间,加入了父类的执行顺序。这个其实也很好理解:在子类的实例构造方法之前,确实需要知道父类的信息,因为子类要从父类那里继承一些东西。这就好比,没有老子,哪来的儿子呢,呵呵。 这里需要特别注意的是,并不是每次实例化都是上面的顺序。因为静态的成员只是在第一次实例化的时候执行,以后再实例化都不会在执行。很好理解,静态的成员意味着大家共享,且只有这一个。第一次实例化得到静态成员后,以后大家都共享,再次实例化,没有必要也不允许执行静态成员的部分。 补充说明: 1、构造引用类型的对象时,调用实例构造方法之前

C++ 构造方法

和自甴很熟 提交于 2019-11-27 01:26:04
1、构造方法的作用是设置数据成员的初始值。 2、定义一个类Person的实例person的时候,必定会调用Person的构造方法。调用构造方法分为两个步骤:第一步使用初始化列表,第二步在构造方法内部对成员赋值。 3、对于初始化列表,肯定会执行。如果用户没有显式的调用,就会隐式的调用。然后才执行第二步,在构造方法内部赋值。 4、对于初始化列表,对于隐式或者显式中没有初始化的成员,成员的取值取决于下面的情况:   a、如果成员是类类型,使用默认构 造方法。(注:对于这种情况,必须保证成员具有默认构造方法)   b、如果是内置类型,分为下面两种情况:     b1、person是全局变量,初始化为0     b2、person是局部变量,不初始化,为oxcccccccc 5、对成员设置一个初始值,在第一步或者在第二步都能达到同样的效果。但是下面几种情况必须在第一步做:   a、const对象   b、引用类型的对象   为什么?因为const对象和引用类型的对象必须进行初始化,因此必须在初始化列表中进行。 注:0xcccccccc:没有初始化,调试的时候都是这个东西,程序不能访问这个地址。   0x00000000:是Null,不指向任何东西。 转载于:https://www.cnblogs.com/nzbbody/p/3365572.html 来源: https://blog.csdn

复制控制

…衆ロ難τιáo~ 提交于 2019-11-27 01:25:58
1、对于构造方法,如果没有声明任何一个构造方法,编译器会自动生成一个Default构造方法。 2、对于Copy构造方法,Copy赋值操作符,析构方法,如果没有声明,编译器会自动生成相应的方法。 3、如果不想使用编译器自动生成的构造方法,就明确表示拒绝。 4、对于Copy构造方法和Copy赋值操作符,使用private禁止外部访问,为了避免成员方法和友元方法访问,对这类方法只声明,不定义,这样的话,到调用Copy构造或者Copy赋值的时候,就会导致link错误。   boost库中的nonecopyable,就是这样一个类,如果想让自己的类禁止copy构造和copy赋值,继承nonecopyable就Ok了。 转载于:https://www.cnblogs.com/nzbbody/p/3370823.html 来源: https://blog.csdn.net/weixin_30799995/article/details/99234454

C++ 初始化与赋值

巧了我就是萌 提交于 2019-11-27 01:25:14
1、初始化与赋值的区别:   二者的区别不是看,是否有=这个赋值操作符,而是看操作的时候,对象是否已经有值。   初始化:创建对象,并给它设置初始值。   赋值:对象已经有值,擦除对象的当前值,并使用新值代替。 2、初始化分为直接初始化和copy初始化。   直接初始化:直接调用与实参匹配的构造方法。   copy初始化:也叫copy构造,总是调用copy构造方法。copy构造方法就是这样的,Person(const Person& rhs),也就是根据已有的对象,copy对象的内容,形成一个副本。 3、一方面:定义对象的时候,肯定调用某个构造方法进行了初始化,包括显示或者隐式。另一方面,对象的初始化必须是在定义的时候进行。这意味着一旦对象定义了,想修改对象,不可能再次初始化对象,只能通过赋值。 4、 Person p1 = p2; 这个 语句调用copy构造,为什么?   第一,定义对象p1的时候,肯定要调用一个构造方法,进行初始化,不可能调用赋值操作符;   第二,赋值的前提是,p1已经有值了,定义p1的时候,p1是没有值的,只能初始化。 5、 copy构造是一种特殊的构造方法,copy赋值和copy构造虽然做的事情相同,但二者有很大的区别。   copy构造创建一个新的对象,因为是构造方法,没有返回值。   copy赋值修改内容,并且返回自身的引用

C++ 对象没有显式初始化

生来就可爱ヽ(ⅴ<●) 提交于 2019-11-27 01:23:18
C++ 对象没有显式初始化,结果是什么? 首先考虑非静态对象 1、方法内的局部对象:   a、类类型:调用default构造方法   b、基本类型:值不确定 2、类中的数据成员:   a、类类型:调用default构造方法   b、基本类型:值不确定 注意:Person p; 调用default构造方法,不能使用 Person p(),对于Person p(),编译器会认为声明一个方法。当然也可以使用 Person p = Person(); 考虑静态对象: 1、方法内的局部对象:   a、类类型:调用default构造方法,注意:类对象中的基本类型对象,即使没有显式初始化,也会初始化为0   b、基本类型:0 2、类中的数据成员:   a、类类型:调用default构造方法   b、基本类型:0 转载于:https://www.cnblogs.com/nzbbody/p/3437472.html 来源: https://blog.csdn.net/weixin_30865427/article/details/99234527

【20】宁以pass-by-reference-to-const替换pass-by-value

二次信任 提交于 2019-11-27 01:21:23
1、首先理解需求,被调用方法修改了形参,如果期望在主调方法中的实参也发生变化,必须使用pass-by-reference。因为C++缺省情况下(继承C方式),以by-value传递对象,在被调方法中修改的是实参的副本。 2、在被调方法中,必须修改形参,但是期望主调方法中的实参不发生变化,这种情况下,必须使用pass-by-value。 3、在被调方法中,不修改形参。应该使用pass-by-reference-to-const替换pass-by-value(有例外情况)。为什么?   a、因为pass-by-value的成本大。要创建新对象,调用构造方法和析构方法。主要有:父类构造方法-->父类字段构造-->子类构造方法-->子类字段构造-->子类析构方法-->撤销子类字段(子类合成析构方法)-->父类析构方法-->撤销父类字段(父类合成析构方法)。使用pass-by-reference-by-const没有这些成本;   b、使用pass-by-value会造成对象切割,这往往不是程序员所期望的。 4、在C++编译器底层,引用是用指针实现的,因此传引用本质上就是传递指针,进行整体拷贝。因此,对于基本类型或者本身就是指针(STL中的迭代器和方法对象)的,没有必要再使用pass-by-reference,使用pass-by-value是一样的。 5、使用pass-by

C++ 变量初始化规则

隐身守侯 提交于 2019-11-27 01:21:20
1、定义变量的时候,如果没有初始化,它的值是什么呢?   它的值取决于变量的类型和变量定义的位置。 2、考虑基本类型的变量,定义时没有初始化。如果定义在方法外部,初始化为0,如果定义在方法内部,不被初始化。使用未初始化的变量,导致未定义行为。未初始化的变量事实上,也有一个值,这个值是随机的。因此强烈建议,基本类型的变量都要初始化,也就是方法内部的变量。 3、考虑类类型的变量,定义时没有初始化。不管定义在哪里,都会调用默认构造方法,这种情况下,必须提供默认构造方法,如果没有,编译出错。也就是说,对于类类型的变量,不存在没有初始化的情况,因为没有显式初始化,会调用默认构造方法进行隐式初始化。 转载于:https://www.cnblogs.com/nzbbody/p/3509506.html 来源: https://blog.csdn.net/weixin_30343157/article/details/99234584

C++ 构造和析构

别说谁变了你拦得住时间么 提交于 2019-11-27 01:21:09
1、继承关系可认为,子类在父类的基础上进行。从这个角度讲,可把它认为穿衣脱衣的过程。穿衣是:先穿内衣,再穿外套。脱衣是:先脱外套,在脱内衣。构造是:先调用父类构造方法,再调用子类构造方法。析构是:先调用子类析构方法,再调用父类析构方法。 2、构造可分为两个步骤:初始化列表和方法内赋值。前者的使用场景是:初始化,即copy构造。后者的使用场景是:赋值,即copy赋值。   a、对于类类型,如果没有在初始化列表中显式初始化,会进行隐式初始化,调用默认构造方法。因此,没有默认构造方法的类成员,必须显式初始化。   b、对于基本类型,如果没有在初始化列表中显式初始化,不会进行隐式初始化。初始值依赖于对象的作用域:局部对象不被初始化,为0xcccccccc(并不是初始化为随机值),全局对象初始值为0。   c、在初始化列表或者赋值阶段,都可以达到同样的效果。但是,对于类类型,如果在赋值阶段进行,相当于执行了一次copy构造(调用默认构造方法),一次copy赋值,因此,对于类类型,应该使用初始化列表,效率高。对于基本类型,因为没有隐式初始化,在初始化列表或者赋值阶段,都是一样的。   d、但是有三种情况必须在初始化列表中进行:d1、没有默认构造方法的类类型,因为没有显示初始化,会进行隐式初始化,调用默认构造方法,导致编译出错;d2、const对象,必须初始化;d3、引用类型,必须初始化。  

stack对象与heap对象

守給你的承諾、 提交于 2019-11-27 01:18:56
从高地址到低地址,分别是stack,heap,static object,stack地址往下增长,heap地址往上增长。只要记住:stack栈顶地址反而小,就知道往下增长了。 禁止产生堆对象 1、产生堆对象使用new operator,可认为new operator有三个过程:   a、使用operator new操作符搜索可用的内存,分配一块内存;   b、在这块内存上,调用构造方法构造一个对象;   c、返回地址。 2、要禁止产生堆对象,可以声明类的operator new为private,禁止分配内存就好了。为了保持一致性,将operator delete也重载为private。 3、注意:new operator不能改变它的行为,operator new是可以重载的。 禁止产生栈对象 1、对于栈对象,栈顶指针挪出一块内存,调用构造方法直接构造对象,离开作用域,调用析构方法。 2、因此,要禁止产生栈对象。可以将构造方法或者析构方法声明为private。 3、将构造方法声明为private,那么问题来了,这将导致无法在类的外部使用new 创建堆对象,为什么?   因为new 产生堆对象也要在分配的内存上调用构造方法。private只能在类的内部使用,因此只能在类的内部使用new 创建堆对象,这就需要重新暴露一个接口,返回堆上创建的对象。也就是静态方法GetInstance。注意

【M5】对定制的“类型转换函数”保持警觉

两盒软妹~` 提交于 2019-11-27 01:17:36
1、隐式类型转换有两种情况:单个形参构造方法和隐式类型转换操作符。注意:隐式类型转换不是把A类型的对象a,转化为B类型的对象b,而是使用a对象构造出一个b对象,a对象并没有变化。 2、单个形参构造方法包括两种情况:声明只有单个形参;或者声明有多个形参,但是除了第一形参,其他的形参都有默认值,也就是说,只要单个形参就能构造对象。   注意:默认形参必须从右向左进行。思考为什么?   调用方法的时候,从左到右使用实参初始化形参,没有提供实参,就使用默认形参值,因此默认形参必须从右向左进行。比如,有5个形参,后面三个有默认值,调用方法的时候,提供三个实参,后面两个使用默认值。 3、隐式类型转换操作符,是一种特殊的方法,可以认为没有形参,没有返回方法,重载了目标类型的方法。 4、隐式类型转换可能在非预期的情况下进行。也就是说,程序员本来没有这个意图,但是编译器为了使方法调用成功,偷偷地进行了隐式转换。因此,隐式类型转应该尽量避免。 5、对于隐式类型转换操作符,最好不要提供,而是应该提供一个AsXXX()方法。 6、对于单个形参构造方法,有两种办法。   a、对于构造方法使用explicit,可以禁止隐式类型转换。这种情况下,可以显式地进行隐式类型转换。   b、增加一个代理类。这是因为,隐式类型转换最多只能进行一次。增加代理类,相当于需要进行两次隐式转换才能成功。这种情况下,编译器放弃执行