iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C++中如何实现对象初始化操作代码
  • 803
分享到

C++中如何实现对象初始化操作代码

2023-06-22 04:06:55 803人浏览 安东尼
摘要

这篇文章给大家分享的是有关c++中如何实现对象初始化操作代码的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。当对象在创建时获得了一个特定的值,我们说这个对象被初始化。初始化不是赋值,初始化的含义是创建变量赋予其一个

这篇文章给大家分享的是有关c++中如何实现对象初始化操作代码的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。

当对象在创建时获得了一个特定的值,我们说这个对象被初始化。初始化不是赋值,初始化的含义是创建变量赋予其一个初始值,而赋值的含义是把当前值擦除,而以一个新值来替代。对象初始化可以分为默认初始化、直接初始化、拷贝初始化以及值初始化。

// new edit on 2020.7.23#pragma once#include <iOStream>using namespace std;class ClassTest { public:  //定义默认构造函数  ClassTest()    {    c[0] = '\0';    cout << "1) ClassTest()" << endl;  }  // 直接初始化  ClassTest(const char* pc)    {    strcpy_s(c, pc);    cout << "2) ClassTest (const char *pc)" << endl;  }  //复制/拷贝构造函数  ClassTest(const ClassTest& ct)    {    strcpy_s(c, ct.c);    cout << "3) ClassTest(const ClassTest& ct)" << endl;  }  //重载赋值操作符  ClassTest& operator=(const ClassTest& ct)    {    strcpy_s(c, ct.c);    cout << "4) ClassTest& operator=(const ClassTest &ct)" << endl;    return *this;  } private:  char c[256];};ClassTest func(ClassTest temp) { return temp; }int demo_test() {  cout << "ct1: ";  ClassTest ct1("ab");  // 直接初始化  cout << "ct2: ";  ClassTest ct2 = "ab"; // 直接初始化    cout << "ct3: ";  ClassTest ct3 = ct1;  // 复制初始化  cout << "ct4: ";  ClassTest ct4(ct1);   // 复制初始化  cout << "ct5: ";  ClassTest ct5 = ClassTest();  // 默认构造函数    cout << "\nct6: "; // 依次調用 1)、2)、4),即默认、直接、重载  ClassTest ct6;    ct6 = "caoyan is a Good boy!";   cout << "\nct7: ";    ClassTest ct7;  // 依次調用 1)、3)、3)、4)  ct7 = func(ct6);  return 0;}

old code:

// (1)默认初始化int i1;//默认初始化,在函数体之外(初始化为0)  int f(void)  {  int i2;//不被初始化,如果使用此对象则报错  }  string empty;//empty非显示的初始化为一个空串,调用的是默认构造函数  // (2)拷贝初始化string str1(10,'9');//直接初始化  string str2(str1);//直接初始化  string str3 = str1;//拷贝初始化   // (3)值初始化vector<int> v1(10);//10个元素,每个元素的初始化为0  vector<string> v2(10);//10个元素,每个元素都为空   int *pi = new int;//pi指向一个动态分配的,未初始化的无名对象  string *ps = new string;//初始化为空string  int *pi = new int;//pi指向一个未初始化的int  int *pi = new int(1024);//pi指向的对象的值为1024  string *ps = new string(10,'9');/  cout << "ct3: ";  ClassTest ct3 = ct1; //复制初始化  cout << "ct4: ";  ClassTest ct4(ct1); //直接初始化  cout << "ct5: ";  ClassTest ct5 = ClassTest(); //复制初始化  cout << "ct6: ";  ClassTest ct6; //复制初始化  ct6 = "caoyan is a good boy!";  cout << "ct7: ";  ClassTest ct7;  ct7 = func(ct6);  return 0;}

测试结果:

C++中如何实现对象初始化操作代码

我们可以看到,比较复杂的是ct6和ct7,其中ct6还是比较好理解的,ct7这种情况比较难懂,为什么会有两个拷贝构造函数的调用????

第一次拷贝构造函数的调用:第一次很简单,是因为函数参数的传递,将ct6作为参数传递给temp,用ct6的值初始化temp会调用拷贝构造函数;

第二次拷贝构造函数的调用:因为要返回一个ClassTest对象,我们的编译器怎么做????首先它将temp对象拷贝到func函数的上一级栈帧中,它的上一级栈帧是main函数的栈帧,那么当函数返回时,参数出栈,temp对象的内存空间就会被收回,但是它的值已经被拷贝到main栈帧的一个预留空间中,所以从temp到预留空间的拷贝也是调用拷贝构造函数,最后一步就是给ct7赋值,毫无疑问调用赋值构造函数;对栈帧不同的同学可以看看《程序员的自我修养》一书,里面讲得很详细!

2、初始化列表、构造函数与=赋值之间的区别

总所周知,C++对象在创建之时,会由构造函数进行一系列的初始化工作。以没有继承关系的单个类来看,除了构造函数本身的产生与指定,还涉及到初始化步骤,以及成员初始化方式等一些细节,本篇笔记主要对这些细节进行介绍,弄清C++对象在初始化过程中一些基本运行规则。

构造函数指定

通常,我们在设计一个类的时候,会为这个类编写对应的default constructor、copy constructor、copy assignment operator,还有一个deconstructor。即便我们仅仅编写一个空类,编译器在编译时仍旧会为其默认声明一个default constructor、copy constructor、copy assignment operator与deconstructor,如果在代码里面存在着它们的使用场景,那么这个时候编译器才会创建它们。

class MyCppClass {}

一旦我们为一个类编写了default constructor,那么编译器也就不会为其默认生成default constructor,对于其他几个函数也一样。对于编译器默认生成的constructor来说,它会以一定规则对每一个数据成员进行初始化。考虑到成员初始化的重要性,在编写自己的constructor时就需要严谨认真了,特别是在类的派生与继承情况下这点显得尤为重要。对于copy constructor和assignment operator的运用场景,这里不得不多说一点,见如下代码:

#include <iostream> using std::cout;using std::endl; class MyCppClass{public:    MyCppClass()    {        std::cout <<"In Default Constructor!" <<std::endl;    }     MyCppClass(const MyCppClass& rhs)    {        std::cout <<"In Copy Constructor!" <<std::endl;    }     MyCppClass& operator= (const MyCppClass& rhs)    {        std::cout <<"In Copy Assignment Operator!" <<std::endl;         return *this;    }}; int main(){    MyCppClass testClass1;                 // default constructor    MyCppClass testClass2(testClass1);     // copy constructor    testClass1 = testClass2;               // copy assignment operator     MyCppClass testClass3 = testClass1;    // copy constructor     return 0;}

执行结果:

C++中如何实现对象初始化操作代码

这里需要注意的是,一般情况下我们总是以为在‘='运算符出现的地方都是调用copy assignment operator,上

面这种情况却是个例外。也就是,当一个新对象被定义的时候,即便这个时候是使用了'='运算符,它真实调用的是初始化函数copy constructor,而不是调用copy assignment operator去进行赋值操作。

Why初始化列表

一个对象在初始化时包括了两个步骤:

首先,分配内存以保存这个对象;

其次,执行构造函数。

在执行构造函数的时候,如果存在有初始化列表,则先执行初始化列表,之后再执行构造函数的函数体。那么,为什么会引入初始化列表呢?

C++与C相比,在程序组织上由“以函数为基本组成单位的面向过程”变迁到“基于以类为中心的面向对象”,与此同时类也作为一种复合数据类型,而初始化列表无非就是进行一些数据的初始化工作。考虑到这里,也可以较为自然的推测初始化列表与类这种数据类型的初始化有着关联。

在引入初始化列表之后,一个类对应数据成员的初始化就存在有两种方式。下面是类的数据成员类型分别为内置类型、自定义类型时的一个对比。 

// 数据成员类型为内置类型class MyCppClass{public:    // 赋值操作进行成员初始化    MyCppClass     {        counter = 0;    }        // 初始化列表进行成员初始化    MyCppClass : counter(0)    {    }private:    int    counter;}

当类的数据成员类型为内置类型时,上面两种初始化方式的效果一样。当数据成员的类型同样也为一个类时,初始化的过程就会有不一样的地方了,比如:

// 数据成员类型为自定义类型:一个类class MyCppClass{public:    // 赋值操作进行成员初始化    MyCppClass(string name)     {        counter = 0;        theName = name;    }    // 初始化列表进行成员初始化    MyCppClass : counter(0), theName(name)    {    }private:    int    counter;    string theName;}

在构造函数体内的theName = name这条语句,theName先会调用string的default constructor进行初始化,之后再调用copy assignment opertor进行拷贝赋值。而对于初始化列表来说,直接通过copy constructor进行初始化。

明显起见,可以通过如下的代码进行测试。

#include <iostream>#include <string> class SubClass{public:    SubClass()    {        std::cout <<" In SubClass Default Constructor!" <<std::endl;    }     SubClass(const SubClass& rhs)    {        std::cout <<" In SubClass Copy Constructor!" <<std::endl;    }     SubClass& operator= (const SubClass& rhs)    {        std::cout <<" In SubClass Copy Assignment Operator!" <<std::endl;         return *this;    }}; class BaseClass{public:    BaseClass(const SubClass &rhs)    {        counter = 0;        theBrother = rhs;        std::cout <<" In BaseClass Default Constructor!" <<std::endl;    }     BaseClass(const SubClass &rhs, int cnt):theBrother(rhs),counter(cnt)    {        std::cout <<" In BaseClass Default Constructor!" <<std::endl;    }     BaseClass(const BaseClass& rhs)    {        std::cout <<" In BaseClass Copy Constructor!" <<std::endl;    }     BaseClass& operator= (const BaseClass& rhs)    {        std::cout <<" In BaseClass Copy Assignment Operator!" <<std::endl;         return *this;    }private:    int counter;    SubClass theBrother;}; int main(){    SubClass subClass;     std::cout <<"\nNo Member Initialization List: " <<std::endl;    BaseClass BaseClass1(SubClass);     std::cout <<"\nMember Initialization List: " <<std::endl;    BaseClass BaseClass2(SubClass, 1);     return 0;}

执行结果:

C++中如何实现对象初始化操作代码

也就是,在涉及到自定义类型初始化的时候,使用初始化列表来完成初始化在效率上会有着更佳的表现。这也是初始化列表的一大闪光点。即便对于内置类型,在一些情况下也是需要使用初始化列表来完成初始化工作的,比如const、references成员变量。这里有篇笔记,对初始化列表有着非常详尽的描述。

几个初始化名词

在阅读《Accelerated C++》中文版时,总是碰到“缺省初始化”、“隐式初始化”以及“数值初始化”,最初在理解这几个名词的时候几费周折,总觉得为什么一个初始化操作造出了如此多的名词,为此没少花时间来弄清楚它们之间的关系。

为了更好的理解它们,先对C++当中的数据类型进行简单划分。在C++里面,数据类型大致可以分为两种:第一种是内置类型,比如float, int, double等;第二种是自定义类型,也就是我们常用的class, struct定义的类。在对这些类型的数据进行初始化时,差别就体现出来了:对于内置类型,在使用之前必须进行显示的初始化,而对于自定义类型,初始化责任则落在了构造函数身上。

int x = 0;          // 显示初始化xSubClass subClass;  // 依赖SubClass的default constructor进行初始化

上面的名词“缺省初始化”描述的就是当内置类型或者自定义类型的数据没有进行显示初始化时的一种初始化状态。而“隐式初始化”描述的是在该状态下面进行的具体操作方式,比如对于内置类型来说,缺省初始化状态下进行的隐式初始化实际上是未定义的,而自定义类型的隐式初始化则依赖于其constructor。

前面提到过C++不保证内置类型的初始化,但是当内置类型在作为一个类的成员时,在某些特定的条件下该内置类型的成员会被编译器主动进行初始化,对于这个过程也就是所谓的数值初始化。在《Accelerated C++》当中列出了如下的几种情况:

  1. 对象被用来初始化一个容器元素

  2. 为映射表添加一个新元素,对象是这个添加动作的副作用

  3. 定义一个特定长度的容器,对象为容器的元素

测试如下:

#include <iostream> #include <vector> #include <map> #include <string>  using std::cout; using std::endl; using std::vector; using std::map; using std::string;  class NumbericInitTestClass { public:     void PrintCounter()     {         cout <<"counter = " <<counter <<endl;     } private:     int counter; };   int main() {     NumbericInitTestClass tnc;     tnc.PrintCounter();      map<string, int> mapTest;     cout <<mapTest["me"] <<endl;      vector<NumbericInitTestClass> vecNumbericTestClass(1);     vecNumbericTestClass[0].PrintCounter();      return 0; }

对于没有进行初始化的内置类型,是一个未定义的值2009095316,而对于2, 3种情况来说,均被初始化为0,对于第1种情况我还没有想到合适的场景。

C++中如何实现对象初始化操作代码

回过头想想,为了书中的一些相似的名词,去想办法把它们凑在一起总是显得有些牵强附会:)一些规则这里附上几条有关初始化的基本规则,它们多来源于《Effective C++》:

为内置型对象进行手工初始化,因为C++不保证初始化它们。

构造函数最好使用成员初值列(member initialization list),而不要在构造函数体内使用赋值操作。初值列列出的成员变量,其排列次序应该和它们在class中声明的次序相同。

C++不喜欢析构函数吐出异常。

在构造函数与析构函数期间不要调用virtual函数,因为这类调用从不下降至derived class。

copying函数应该确保复制“对象内所有成员变量”及“所有base class成分”。

感谢各位的阅读!关于“C++中如何实现对象初始化操作代码”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!

--结束END--

本文标题: C++中如何实现对象初始化操作代码

本文链接: https://www.lsjlt.com/news/302320.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C++中如何实现对象初始化操作代码
    这篇文章给大家分享的是有关C++中如何实现对象初始化操作代码的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。当对象在创建时获得了一个特定的值,我们说这个对象被初始化。初始化不是赋值,初始化的含义是创建变量赋予其一个...
    99+
    2023-06-22
  • C++中的对象初始化操作代码
    当对象在创建时获得了一个特定的值,我们说这个对象被初始化。初始化不是赋值,初始化的含义是创建变量赋予其一个初始值,而赋值的含义是把当前值擦除,而以一个新值来替代。对象初始化可以分为默...
    99+
    2022-11-12
  • C#中如何初始化对象
    C#中如何初始化对象,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。具体示例如下:classPoint  {  publicintX{...
    99+
    2023-06-17
  • C#中怎么实现对象初始化
    本篇文章给大家分享的是有关C#中怎么实现对象初始化,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。C#对象初始化器 (Object Initializers) :.NET2.0框...
    99+
    2023-06-17
  • Python 如何用一行代码实现for循环初始化数组
    我就废话不多说了,大家还是直接看代码吧~ # 用一行代码实现for循环初始化数组 o = 10 b = [ o + u for u in range( 10 ) ] print...
    99+
    2022-11-11
  • PHP中如何实现对象的并发操作?
    在PHP中,对象的并发操作是一个非常重要的主题,因为它可以提高应用程序的性能和响应速度。在本文中,我们将讨论如何在PHP中实现对象的并发操作。 首先,让我们先了解一下PHP中的并发操作是什么意思。简单来说,并发操作是指多个线程或进程同时执行...
    99+
    2023-10-22
    对象 并发 shell
  • GO 存储 API 对象:如何在代码中实现?
    GO 是一种功能强大的编程语言,它在编写高性能应用程序方面非常有用。GO 应用程序通常需要访问存储库来读取或写入数据,因此 GO 存储 API 对象是必不可少的。在本文中,我们将介绍如何在代码中实现 GO 存储 API 对象。 一、了解 ...
    99+
    2023-06-28
    存储 api 对象
  • 如何在C#项目中实现对象序列化XML
    这篇文章给大家介绍如何在C#项目中实现对象序列化XML,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。首先,需要用到的是这两个命名空间(主要)using System.Xml;using System...
    99+
    2023-06-06
  • Java 对象如何在 Linux 中实现重定向操作?
    在 Linux 中,重定向是一个常见的操作。通过重定向,我们可以将命令的输出或输入重定向到文件中,或者将一个命令的输出传递给另一个命令作为输入。在 Java 中,我们也可以实现重定向操作,这个过程需要用到 Java 中的标准输入流、标准输...
    99+
    2023-10-10
    重定向 linux 对象
  • PHP中的对象和Numpy:如何实现更高效的代码?
    在编写高效的代码时,对于使用的语言和工具的了解是非常重要的。PHP和Numpy都是广泛使用的工具,但它们在处理数据和实现算法时有很大的不同。本文将介绍如何在PHP中使用对象和Numpy来实现更高效的代码。 一、PHP中的对象 PHP是一种...
    99+
    2023-07-08
    apache 对象 numpy
  • 重定向操作如何在 Java 和 Linux 中实现对象传递?
    重定向是指将输出从一个地方转移到另一个地方。在 Java 和 Linux 中,重定向可以实现对象传递,使得程序可以更加灵活地处理数据。本文将介绍重定向在 Java 和 Linux 中的实现方式,并提供相应的演示代码。 一、Java 中的重...
    99+
    2023-10-10
    重定向 linux 对象
  • C#中如何使用属性和自动实现属性简化代码
    C#中如何使用属性和自动实现属性简化代码,需要具体代码示例在C#编程中,使用属性和自动实现属性可以帮助我们简化代码,提高代码的可读性和可维护性。属性允许我们通过封装字段来访问和更改对象的状态,而自动实现属性则进一步简化了属性的创建过程。属性...
    99+
    2023-10-22
    属性(属性) 自动实现属性(自动属性) 代码简化(简化代码)
  • PHP 实时编程算法中,如何使用对象来实现更高效的代码?
    PHP是一种广泛使用的编程语言,它提供了多种算法来帮助程序员实现更高效的代码。其中一个非常有用的算法就是实时编程算法。在实时编程算法中,我们需要快速处理大量数据,这就需要使用高效的数据结构和算法来优化代码。本文将介绍如何使用对象来实现更高效...
    99+
    2023-11-13
    实时 编程算法 对象
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作