C++PrimerPlus学习之类和动态内存分配

版权声明:转载之前请说你是博主的粉丝哦。 https://blog.csdn.net/qq_34921856/article/details/83658301

复制构造函数

  • 如果没有定义,编译器将默认提供复制构造函数
  • 原型
    Class_name(const Class_name &)
    StringBad(const StringBad &)
    
  • 何时调用
    StringBad ditto(motto);
    StringBad metoo=motto;
    StringBad also=StringBad(motto);
    StringBad *pStringBad = new StringBad(motto);
    
  • 有何功能
    当类的成员是使用new初始化的,指向数据的指针,而不是数据本身时,我们需要重新定义复制构造函数。
    需要注意的是,由于按值传递对象将调用复制构造函数,因此如果有参数列表有值传递的函数时,请改成使用引用传递的函数。

赋值运算符

  • 同复制构造函数的功能类似。

  • 原型

    Class_name & Class_name::operator=(const Class_name &);
    StringBad & StringBad::operator=(const StringBad &);
    
  • 何时调用

    StringBad headline1("Hello World");//复制构造函数
    StringBad knot;
    knot = headline1;//赋值运算符
    
  • 有何功能

    • 同复制构造一样,当成员函数含有指针的时候,同样需要手动创建
    • 手动创建时需要注意一些事项
      • 需要先释放目标对象之前使用new分配的旧数据
      • 应尽量避免将对象赋值给本身 – 否则可能会在赋值前释放其旧数据
      • 函数返回一个指向调用对象的引用
      • 由此可知赋值函数并不创建新的对象
    • 可以进一步重载赋值运算符,以支持其他类型到此类的转换
    • 如果目前还没有必要实现复制构造和赋值运算符,但也不希望有复制或赋值现象发生,可将这两个函数声明为private且忽略其实现(将永远不会被调用)

中括号运算符重载

  • 简单实现

    //声明
    char & operator[](int i);
    //定义
    char & String::operator[](int i)
    {
    	return str[i];
    }
    
  • 当变量被const修饰时,使用该方法会报错,因为上述方法无法保证不修改数据。故需提供另一个仅供const String对象的operator版本。

    const char & String::operator[](int i)
    {
    	return str[i];
    }  
    

静态类成员函数

  • 声明必须包括static,定义时不能包含关键字static。

    //声明
    static int HowMany();
    //定义
    int String::HowMany()
    {
      ...;
    }
    //调用
    int count = String::HowMany();
    
  • 使用规则

    • 不能通过对象调用静态成员函数
    • 不能使用this指针
    • 如果静态成员函数是在公用部分声明的,则可以使用类名和作用域解析运算符来调用它

类中的new与delete

  • 应注意的事项

    • 如果构造函数中使用new来初始化指针成员,则应在析构函数中使用delete
    • new和delete必须相互兼容,new对应delete,new[]对应于delete[]
    • 如果有多个构造函数,则必须以相同的方式使用new。
  • 应当定义一个复制构造函数,通过深复制将一个对象初始化为另一个对象

    String::String(const String& s) {
      len = s.len;
      str = new char[len+1];          // 分配空间 -- 深复制
      strcpy(str, s.str);
    }
    
  • 应当定义一个赋值运算符,通过深度复制将一个对象复制给另一个对象

    扫描二维码关注公众号,回复: 3983610 查看本文章
    String& String::operator=(const String& s) {    // 返回引用 -- 防止创建额外副本
      if(this == &s) return *this;            // 自我赋值时 -- 直接返回this
      delete[] str;                           // 清理旧数据
      len = s.len;
      str = new char[len+1];
      strcpy(str, s.str);
      return *this;
    }
    

有关返回对象的说明

  • 返回指向const对象的引用

    • 返回对象将调用复制构造函数,而返回引用不会。
    • 效率更快。
    • 不能返回指向临时变量的引用。
    • 参数为const类型的引用的返回值也应该为const类型的引用。
    • 返回const引用的函数可以赋值给此类型变量(赋值了一下),也可赋值给const类型的引用,但是不能赋值给非const的引用
    const int &Max(const int &a,const int &b)
    {
      if(a>b)return a;
      return b;
    }
    
    int main()
    {
      int a=2,b=5;
      int c=Max(a,b);//隐式转换了一下
      const int &d=Max(a,b);
      c++;
      cout<<c<<' '<<d<<endl;
    }
    
    
  • 返回指向非const对象的引用

    • 有时候是为了提高效率 – 如重载赋值运算符
      • 也可以返回对象,也可以返回引用 – 返回引用可避免创建新的副本
    • 有时候是为了必须这样做 – 如重载 cout的<< 运算符
      • ostream对象没有公有的复制构造函数
  • 返回对象

    • 如果返回的对象是被调用函数中的局部变量,则必须以对象的形式返回。(如重载+运算符)
    • 存在复制构造函数创建返回的对象的开销,但无法避免
  • 返回const对象

    • 主要是为了防止函数(或重载了操作符的表达式)本身成为左值而导致的一些问题
    • a+b=k,如果使用const则会返回错误信息

使用指向对象的指针

  • 定位new运算符
    • 需显式调用析构函数

    • 删除顺序与创建顺序相反

      char* buffer = new buffer[maxn];
      Point* p1 = new(buffer) Point;
      Point* p2 = new(buffer + sizeof(Point)) Point(1, 2);
      p2->~Point();
      p3->~Point();
      delete[] buffer;
      

猜你喜欢

转载自blog.csdn.net/qq_34921856/article/details/83658301