C++笔记6 类和复制控制部分

本文探讨了C++中类的设计原则,包括成员变量初始化、构造函数使用、复制控制等核心概念。强调了数据抽象、封装的重要性,并提供了实用建议。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.类可以没有成员,需要注意的是类的成员可以是型别名。
2.构造函数应该使用一个构造函数初始化列表,来初始化对象的数据成员。针对这一条,多说几句。首先,初始化列表可以将成员变量直接初始化。其次,有些数据成员必须要从初始化列表中初始化。从概念上讲,构造函数分两个阶段执行,1初始化阶段;2普通的计算阶段,计算阶段由构造函数体中的所有语句组成。不管成员是否在构造函数的初始化列表显示初始化,类类型的数据成员总是在初始化阶段初始化,初始化发生在计算阶段开始之前。在构造函数初始化列表中没有显示提及的每个成员,使用与初始化变量相同的规则初始化。运行该类型的默认构造函数,来初始化类类型的数据成员,内置或复合类型的成员的初始化依赖于对象的作用域。没有默认构造函数的类类型成员,以及const或引用类型的成员,不管是哪种类型,都必须在构造函数初始化列表中初始化。
记住,可以初始化const对象或引用类型的对象,但是不能对他们赋值,所以初始化他们的唯一机会就是在构造函数的初始化列表。
3.const必须同时出现在声明和定义中,若只出现在其中一处,就会出现编译时错误。
4。如果类具有内置类型或者复合类型,定义构造函数为好,类的使用者做初始化的工作的话容易出错
5.数据抽象和封装的好处:a,避免类内部出现无意的,可能破坏对象的用户级错误;b,需求改变的话无需改变用户级代码。
6.重载的成员的形参数量和类型不能完全相同。
7.在普通的非const成员函数中,this的类型是指向类类型的const指针。可以改变this指向的值,但是不能改变this本身的值,也就是this保存的地址。不能从const成员函数返回指向类对象的普通引用。基于成员函数是否为const可以重载成员函数,基于指针形参是否指向const,可以重载一个函数,as well。
8.可变数据成员,mutable。const成员函数可以改变mutable成员。
9.很重要的一个建议:用于公共代码的私有使用函数。像在二叉树中,如果插入一个节点,可能要调用递归函数insert(node, value)来完成,但是首次调用传入的实参应该是root指针,这个指针是二叉树的类的私有成员,所以可以定义一个类成员函数insert(value)然后inset函数调用类的私有函数
insert_aux(root, value)来实现。
10.构造函数不能声明为const。尽可能避免使用成员才初始化其他成员。并多使用默认实参,减少代码重复。
11.如果类包含内置类型或者复合类型成员,不应该依赖合成的默认构造函数,要自己定义。
12.使用默认构造函数定义一个对象的方式是去掉最后的空括号。T t = T() 或者 T t定义方式。不能使用T t()  这样编译器会把他看成函数声明。
13.抑制构造函数定义的隐式转换。explicit 关键字只能用于类内部的构造函数声明上,类外定义不在重复。explicit可以防止编译起将构造函数作为转换操作符。
14.通常一个类应该有一个默认构造函数。
15.通常,单形参构造函数应该为explicit,当需要转换时,可以显示地构造对象。
16.static函数没有this指针。static成员是类的组成部分,但是不是任何对象的组成部分,所以没有this指针。也因为这一点,static成员函数不能是const的。static成员函数也不能被声明为虚函数。
17.static数据成员必须在类定义体的外部定义。
18.特殊的整型const static成员。只要初始化式是一个常量表达式,const static数据成员就可以在类的定义体中初始化。但是它仍然必须在类的定义体之外进行定义。

复制控制部分:
1.当将该类型的对象传递给函数或者从函数返回类型的对象时,将隐式使用复制构造函数。
2.在对象超出作用域,调用析构函数的时候,不会自动执行static数据成员的析构函数。包括退出程序
3.很明显的一种需要自己定义复制控制成员的情况:类具有指针成员。
4.当用于类类型对象时,初始化的复制形式和直接形式有所不同:直接初始化直接调用参与匹配的构造函数,复制初始化总是调用复制构造函数。复制初始化首先使用指定构造函数创建一个临时对象,然后用复制构造函数将那个临时对象复制到正在创建的对象。
5.通常上述二者存在的差异只是低级别优化,然而,对于不支持复制的类型或者使用非explicit构造函数的时候,他们有本质区别。举例说明如下:ifstream file1("filename");直接初始化形式。这样是可以的。但是ifstream file2 = "filename"是会报错的,因为它的拷贝构造函数是私有的,流对象是不支持复制的。item = string("121-3212-12");如果item的构造函数不是explicit的,就可以。
6.禁止复制:为了防止复制,类必须显示声明其复制构造函数为private。如iostream类。声明而不定义成员函数是合法的,但是,使用未定义成员的任何尝试将导致链接失败,通过声明private复制构造函数,可以禁止任何复制类类型对象的尝试:用户代码中的复制尝试将在编译时标记为错误,而成员函数和友元中的复制尝试将在链接时导致错误。
7.重要建议:大多数类应该定义复制构造函数和默认构造函数,否则会严重局限类的使用。不允许复制的类对象只能作为引用传递给函数或从函数中返回,他们也不能作为容器的元素。补充:如果一个类没有默认构造函数,他不能:1每个具有这个类的成员的类的构造函数必须传递一个初始的值给它来显示初始化。2)不能用作动态分配数组的元素类型。3)这个类型的静态分配数组必须为每个元素提供一个显式的初始化式。
8.如果类需要复制构造函数则需要赋值操作符
9.复制操作符首先要检查左右操作数是否相同。

 

1.选择重载为成员或非成员实现。赋值,下标,调用,成员访问箭头等必须定义为成员。复合赋值操作符应定义为类的成员,不这样做不会报错。对称的操作符如算数运算符,相等操作符,关系操作符和位操作符,最好定义为普通非成员函数。
2.输出操作符的重载返回ostream的引用。链式操作。ostream为非const,因为写入到流一定会改变。输入操作符第二个形参一定是非const的。要改变。输入操作符必须处理错误和文件结束的可能性。这是输入输出操作符的区别。if(in)……else……reset对象。因为一个复合对象的话,写了一半失败了,之前的写过的也要恢复到之前的状态,否则就不一致了。设计输入操作符时,如果可能,要确定错误回复措施。
3.加法操作符并不改变操作数的状态,所以两个参数声明为const引用。它返回一个新的对象,为了与内置操作符一致,加法返回一个右值,而不是一个引用。
4.定义operator<可能相当有用,这个可以考虑库函数的调用。比如find和sort。
5.操作符的后缀表达式要复杂一点,因为它返回的是加/减之前的状态,而本身又要变化,所以它要记忆一个状态。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值