zoukankan      html  css  js  c++  java
  • 《C++ Primer Plus》读书笔记之十—类和动态内存分配

    第12章 类和动态内存分配

      1、不能在类声明中初始化静态成员变量,这是因为声明描述了如何分配内存,但并不分配内存。可以在类声明之外使用单独的语句进行初始化,这是因为静态类成员是单独存储的,而不是对象的组成部分。注意:静态成员在类声明中声明,在包含类方法的文件中初始化。初始化时使用作用域操作符来指出静态成员所属的类。但如果静态成员是整型或枚举型const,则可以在类声明中初始化。

      2、当使用一个对象来初始化另一个新建对象时,编译器将自动生成一个复制构造函数,因为它创建对象的一个副本。复制构造函数的原型为:classname(const classname &);

      3、C++自动提供了下面的这些函数:①默认构造函数,如果没有定义构造函数②复制构造函数,如果没有定义③赋值操作符,如果没有定义④默认析构函数,如果没有定义⑤地址操作符,如果没有定义

      4、何时调用复制构造函数:新建一个对象并将其初始化为同类现有对象时,复制构造函数都将被调用。例如,假设motto是一个stringbad类对象,则下面4种声明都将调用复制构造函数:

      ①stringbad ditto(motto);②stringbad metto=motto;③stringbad also=stringbad(motto);④stringbad *p=new stringbad(motto);其中②③可能会使用复制构造函数直接创建metto和also,也可能使用复制构造函数生成一个临时对象,然后将临时对象的内容赋给metto和also,这取决于具体的实现。

      5、每当程序生成了对象副本时,编译器都将使用复制构造函数。具体地说,当函数按值传递(创建原始变量的一个副本)或函数返回对象时,都将使用复制构造函数。编译器生成临时对象时,也将使用复制构造函数。

      6、默认的复制构造函数逐个复制非静态构造函数(浅复制),复制的是成员的值。如果成员本身就是类对象,则将使用这个类的复制构造函数来复制成员函数。静态函数不受影响。

      7、如果类中包含了使用new初始化的指针成员,应当定义一个复制构造函数,以复制指向的数据,而不是指针,这也称为深度复制。浅复制也叫成员复制,只是复制指针值,而不会深入挖掘来复制指针引用的结构。

      8、赋值操作符:C++允许类对象赋值,这是通过自动为类重载赋值操作符实现的。这种操作符的原型如下:

      classname & classname::operator=(const classname &);

      9、何时使用赋值操作符:将已有的对象赋给另一个对象时,将使用重载的赋值操作符。注:初始化(创建新对象)总是会调用复制构造函数,而使用=操作符也可能调用赋值操作符。赋值操作符并不创建新的对象。

      10、与复制构造函数相似,赋值操作符的隐式实现也对成员进行逐个复制(浅复制)。如果成员本身就是类对象,则程序将使用为这个类定义的赋值操作符来复制该成员。对于由于默认赋值操作符不合适导致的问题,解决方法是提供赋值操作符(进行深度复制)定义。其实现与复制构造函数相似,但也有一些差别。一个例子:

      stringbad & stringbad::operator= (const stringbad & st)

      {

        if(this==&st)  // 检查自我复制

          return *this;

        delete [] str;  // 释放成员指针以前指向的内存

        len=st.len;

        str=new char[len+1];

        std::strcpy(str,st.str);

        return *this;    // 返回一个指向调用对象的引用

      }

      11、由于静态成员函数不与特定的对象相关联,因此只能使用静态数据成员。

      12、重载>>操作符:

      istream & operator>>(istream & is,string & st)

      {

        char temp[10];  // 假设输入的字符数不多于10

        is.get(temp,10);  // 如果由于某种原因(如到达文件尾,或读取的是一个空行),导致输入失败,istream对象的值将置为false

        if(is)

          st=temp;

        while(is&&is.get()!=' ')  // 丢弃多余的字符

          continue;

        return is;

      }

      13、if(!cin)检测空行!!

      14、可以在一个构造函数中使用new来初始化指针,而在另外一个构造函数中将指针初始化为空(NULL或0),这是因为delete(无论带中括号还是不带)可以用于空指针。

      15、如果函数返回传递给他的对象,可以通过传递引用来提高方法的效率。返回对象将调用复制构造函数,而返回引用不会。

      16、重载操作符<<函数,返回类型必须是ostream &,而不能仅仅是ostream。如果返回类型ostream,将要求调用ostream类的复制构造函数,而ostream没有公有的复制构造函数。

      17、总结:如果方法或函数返回局部对象,则应返回对象而不是指向对象的引用。在这种情况下,将使用复制构造函数来生成返回的对象。如果方法或函数返回一个没有公有复制构造函数(如ostream类)的对象,它必须返回一个指向这种对象的引用。最后,有些方法和函数(如重载的赋值操作符)可以返回对象,也可以返回指向对象的引用,在这种情况下,应首选引用,因为其效率高。

      18、成员初始化列表:classname::classname(int n,int m):mem1(n),men2(0),men3(n*m+2){ //....}从概念上说,这些初始化工作是在对象创建时完成的,此时还未执行括号中的任何代码。对于简单数据成员,使用成员初始化列表和在函数体中使用赋值没有什么区别。不过,对于本身就是类对象的成员来说,使用成员初始化 列表效率更高。注:①这种格式只能用于构造函数。②必须用这种格式初始化非静态const数据成员。③必须用这种格式初始化引用数据成员。

      19、在类中嵌套结构和类声明: 在类声明中声明的结构、类或枚举被称为是被嵌套在类中,其作用域为整个类。这种声明不会创建数据对象,而只是指定了可以在类中使用的类型。如果声明是在类的私有部分进行的,则只能在这个类中使用被声明的类型;如果声明是在公有部分进行的,则可以从类的外部通过作用域解析操作符使用被声明的类型。例如:如果Node是在Queue类的公有部分声明的,则可以在类的外面声明Queue::Node类型的变量。

  • 相关阅读:
    leetcode 1301. 最大得分的路径数目
    LeetCode 1306 跳跃游戏 III Jump Game III
    LeetCode 1302. 层数最深叶子节点的和 Deepest Leaves Sum
    LeetCode 1300. 转变数组后最接近目标值的数组和 Sum of Mutated Array Closest to Target
    LeetCode 1299. 将每个元素替换为右侧最大元素 Replace Elements with Greatest Element on Right Side
    acwing 239. 奇偶游戏 并查集
    acwing 238. 银河英雄传说 并查集
    acwing 237程序自动分析 并查集
    算法问题实战策略 MATCHORDER 贪心
    Linux 安装Redis全过程日志
  • 原文地址:https://www.cnblogs.com/smile233/p/8931865.html
Copyright © 2011-2022 走看看