`
lc52520
  • 浏览: 369198 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

C++隐式成员函数【Z】

阅读更多

这篇文章讲述的是C++提供的一些由编译器自动生成的函数,而这些函数,对你来说,也许是不可知的。在编程的世界中,没有比不可知更让人害怕了。

C++自动提供了以下成员函数:

1.默认构造函数:如果没有定义构造函数

2.复制构造函数:如果没有定义

3.赋值操作符:如果没有定义

4.默认析构函数:如果没有定义

5.地址操作符:如果没有定义

其中,最让人心慌的是复制构造函数。下面我们一个一个来说明:

1.默认构造函数

如果没有定义构造函数,编译器将提供ClassName::ClassName(){ }这样的空的构造函数。这样的函数也可以显式的定义。需要注意的是所有参数都有默认值的构造函数也是默认构造函数。而默认构造函数只能有一个,也就是说不能出现:

ClassName::ClassName(){  }

ClassName::ClassName(int n=0){ }

这样的定义。

2.复制构造函数

复制构造函数其实经常出现在我们的程序中,比如说Pound p=12.5。上一篇文章说过的,这里的实现流程是首先,将12.5转换成一个Pound类,然后将其复制给p。注意,这里跟后面提到的赋值操作符一样, 因为这里的场景是对p进行初始化。如果是Pound p; p=12.5。这样就跟赋值操作符有关了。

其实除了上面说到的这种形式,还有另外一些形式会自动生成复制构造函数,如:

Pound p1;

Pound p2(p1);

Pound p2=p1;

Pound p2=Pound(p1);

Pound *pp2=new Pound(p1)

当然,程序生成对象副本的任何时候,都会使用复制构造函数,比如说函数参数的值传递。

有人问,这种自动的复制构造函数有什么危害啊?怎么我都看不出来?

危害大了。它在于,编译器自动生成的复制构造函数,只会对类成员进行逐个复制。

又有人问,对类成员进行逐个复制,不就满足要求了吗?

非也。大家如果还记得Java里面的深复制跟浅复制,现在可能猜出一二了。

 

比如说,有一个类StringTest,里面的一个类成员是char *str,另外一个类成员是length,也就是说,这个类用来封装一个字符串数组,但是并不是使用数组,而是字符指针,区别就在这里了。 StringTest有一个以字符指针为形参的构造函数,函数中使用str = new char[length+1]来创建字符数组。也有一个析构函数析构函数中使用delete [] str来释放字符数组。

现在定义一个StringTest 的对象string1,用strcpy函数将string.str赋值成"test"。 当然length也要设置好。

现在有一个函数Test(StringTest t){}。注意,不是传引用,而是传值哦。以string1为实参调用Test,即Test(string1) 函数啥也不做。调用这个函数之前,我们打印string1.str,屏幕显示"test"。这是正确的。但是调用完这个函数之后,你再打印 string1.str。你会发现一切已经跟你想的不一样了。屏幕上输入的并不是test,而是无法识别的乱码!!

问题出在哪里呢?!

让我们一起回到案发现场:Test(StringTest t)。肯定是调用函数出问题了。将string1传入函数Test,这是值传递,因此 将会复制string1到t,t是一个临时对象。这时调用的就是复制构造函数 , 他将逐个复制类成员变量。本来呢,这是完全没有问题,可是注意,我们的str是一个指针,复制的时候,也只是会复制一个指针到t,而字符串"test" 呢?在内存中仍然是只有一个! OK,等到函数结束,它将自动调用StringTest类的析构函数来处理t,于是乎delete [] str,删除t中的字符数组,结果连原来的string1的字符数组都删掉了(因为他们本来就是同一个)

乖乖。这就是浅复制了。而原本应该进行的深复制,即对整个字符数组进行复制。这样就不会影响到原来的string1了。

如何改正呢?

当然是显式地定义一个复制构造函数了,形如:

ClassName ::ClassName(const Class _name&)

在显式复制构造函数的定义中,我们进行字符数组的生成和复制的处理,这样就保证了析构一些临时对象的时候,不会影响到原有对象!




分享到:
评论

相关推荐

    C++初始化成员列表.

    一方面,使用初始化成员列表可以避免类成员的隐式默认构造函数的调用,避免了多余的构造和赋值操作,从而提高效率。例如,在下面的例子中,MyClass中的abc成员是ABC类的对象,而ABC类只有带参数的构造函数,没有默认...

    C++面向对象程序设计清考试卷A.doc

    构造函数是特殊的成员函数,用于初始化对象,而静态成员函数则与特定的对象实例无关,它们不属于任何特定对象。 **5. 堆对象的操作** - 创建或删除堆对象需要用到 `new` 和 `delete` 操作符(选项 B 和 C)。`new`...

    用C++进行DLL编程入门

    Point1类中的所有成员函数都是导出的,而Point2类中只有一个成员函数是导出的。 在dlltest.cpp文件中,需要实现这些成员函数。注意这里使用了_declspec(dllexport)和_declspec(dllimport)关键字来控制函数的导出和...

    腾讯_-_C++编码规范.7z

    6. **类型安全**:避免隐式类型转换,尤其是可能导致精度损失或意料之外行为的转换。使用强类型来提高代码安全性。 7. **模板和泛型编程**:合理使用模板可以提高代码复用,但过度使用会导致编译时膨胀。规范可能...

    华为技术有限公司C++语言编程规范,华为技术有限公司c语言编程规范.pdf,C,C++

    《华为技术有限公司C++语言编程规范》是一份深入细致的编程指南,旨在为开发者提供一套在C++编程中应遵循的最佳实践。这份规范不仅适用于华为公司内部开发,也对外界开发者具有很高的参考价值,帮助他们提升代码质量...

    2.const对象-NULL和nullptr-C++中创建对象数组.docx

    例如,在上面的代码中,我们定义了一个名为area的类,其中包括三个成员变量x、y和z,以及三个成员函数printxy、add和go。其中,printxy函数被定义为const,意味着它不能改变类的状态。 在main函数中,我们创建了一...

    C++标识符规则

    3. **函数或类的成员函数**: 如`void print() {}` 4. **自定义类型名**: 如`typedef int Integer;` 5. **标识宏的名字**: 如`#define MAX 100` 6. **宏的参数**: 如`#define ADD(x, y) (x + y)` #### 六、数据类型...

    c++基础语法:构造函数初始化列表

    分配内存,调用构造函数 时,隐式/显示的初始化各数据 成员2.进入构造函数后在构造函数中执行一般计算 使用初始化列表有两个原因: 1.必须这样做:如果我们有一个类成员,它本身是一个类或者是一个结构,而且这个...

    习题5及其解答(第二版).doc

    这些知识点涵盖了C++中结构体和类的基本概念,包括成员访问、运算符优先级、静态成员和常量成员函数的使用,以及友元函数和`this`指针的作用。理解和掌握这些知识点对于深入学习C++编程至关重要。

    C++随手笔记C++随手笔记

    - 成员函数可以是普通的成员函数,也可以是静态成员函数。 - 成员函数可以重载,以提供不同的功能实现。 #### 31. 模式设计 - 桥接模式可以将抽象与实现解耦。 - 单例模式保证一个类只有一个实例,并提供全局访问点...

    C++类的初始化介绍及实现

    首先,我们来看C++中如何在构造函数的成员初始化列表中初始化类的成员。成员初始化列表是一种特殊的语法结构,允许我们在构造函数定义的括号内,以冒号(:)开头,列出成员变量和它们的初始值。这种方式比在构造函数体...

    dll编程入门(C++语言).pdf

    - 当需要导出类时,我们可以在头文件中使用条件宏来控制类和成员函数的导出。例如,`DLL_API`宏可以用于标记类和函数的导出。在DLL的实现文件中,我们定义这个宏为`_declspec(dllexport)`,而在使用DLL的客户端程序...

    (完整版)C++试题(一)附答案.docx

    常数据成员可以在构造函数初始化列表中初始化,且常对象只能调用常成员函数,但常数据成员并不一定是公有的。 13. **友元函数**: 友元函数可以访问类的私有和保护成员,但不是成员函数,使用`friend`关键字声明...

    c++基础语法:构造函数与析构函数

    构造函数是C++类的一个特殊成员函数,它的主要任务是在创建对象时进行初始化。当创建一个类的对象时,构造函数会被自动调用。如果类中没有定义任何构造函数,编译器会自动生成一个默认构造函数,即无参构造函数。...

    《面向对象程序设计》习题三答案.doc

    - 成员函数重载二元运算符时,参数列表中只需要一个参数,因为它隐式地接收当前对象作为第一个操作数。 - 非成员函数重载二元运算符时,参数列表中需要两个参数。 - 示例: ```cpp class MyClass { public: ...

    (完整版)C++试题(一)附答案.pdf

    12. **常成员**:常数据成员可以在构造函数初始化列表中初始化,且常对象只能调用常成员函数,选项B错误。 13. **友元函数**:友元函数可以访问类的所有成员,不仅仅是私有成员,选项B错误。 14. **指针操作**:...

    北京邮电大学C++语言程序设计-----阶段作业1.docx

    `operator+=`是成员函数,返回类型通常是类的引用,以便链式操作。它的形参通常是一个操作数,不是友元函数。 6. 运算符重载:C++中的运算符重载不能增加新运算符,也不能改变操作数个数。但可以为类类型的数据重...

    C++笔试面试题

    #### 四、结构体成员函数调用错误 1. **问题描述**: - 指出了在定义结构体对象时出现的问题。 2. **代码示例**: ```cpp struct Test { Test(int) {} Test() {} void fun() {} }; void main(void) { ...

Global site tag (gtag.js) - Google Analytics