C++ 第十二章 类和动态内存分布

C++ 第十二章 类和动态内存分布,第1张

C++ 第十二章 类和动态内存分布 12.1 动态内存和类
#ifndef D1_STRINGBAD_H
#define D1_STRINGBAD_H

#include 

class stringbad {
private:
    char * str;
    int len;
    static int num_strings;  //静态成员变量,只创建一个静态副本
public:
    stringbad(const char *s );
    stringbad();
    ~stringbad();
    friend std::ostream &operator<<(std::ostream &os, const stringbad &st);
};

#endif //D1_STRINGBAD_H
#include "stringbad.h"
#include 
using std::cout;

int stringbad::num_strings = 0;   //初始化静态变量成员,单独初始化

stringbad::stringbad(const char *s) //构造函数
{
    len = std::strlen(s);
    str = new char[len + 1];
    std::strcpy(str,s);
    num_strings++;
    cout << num_strings << ": "" << str << "" object createdn";
}

stringbad::stringbad()   //默认构造函数
{
    len = 3;
    str = new char[4];
    std::strcpy(str,"C++");
    num_strings++;
    cout << num_strings << ": "" << str << "" default object createdn";
}

stringbad::~stringbad()   //析构函数
{
    cout << """ << str << "" object deleted, ";
    num_strings--;
    cout << num_strings << " leftn";
    delete[] str;

}

std::ostream &operator<<(std::ostream &os, const stringbad &st) {
    os << st.str;
    return os;
}

静态变量和类:

将静态成员num_strings的值初始化为零时,注意,不能在类声明中初始化静态变量,这是因为声明中描述了如何分配内存,但并不分配内存。对于静态成员变量,可以在类声明之外使用单独的语句来进行初始化,这是因为静态类成员是单独存储的,而不是对象的组成部分。初始化是在方法文件中,而不是在类声明文件中进行的,这是因为类声明位于头文件中,如果头文件被多个文件包含,变量就会被多次初始化,引发错误。const变量可以在类声明中初始化静态数据成员:static const int  num_strings = 12;

构造函数和析构函数:

如果类成员是一个指针,构造函数应该先分配足够的内存来存储(使用new动态分配),然后再把内容复制到内存中;

stringbad::stringbad(const char *s) {
    len = std::strlen(s);
    str = new char[len + 1];  //string是一个指针
    std::strcpy(str,s);
    num_strings++;
    cout << num_strings << ": "" << str << "" object createdn";
}

在构造函数中用new分配内存,在析构函数中就要用delete删除内存;

    当对象过期时,指针str也将过期,但是new分配的内存不会被释放,除非使用delete释放,,如果使用new[ ],则释放时用delete [ ] str;

特殊成员函数:

默认构造函数:创建对象时会调用构造函数,如下,定义一个类Klunk,创建对象时:

       Klunk  lunk();

      此时没有传入任何参数,因此调用默认构造函数:

      Klunk::Klunk()

      {};   //里面可以定义默认值

复制构造函数:用于将对象复制到新创建的对象中,即用于初始化过程

       1.函数原型:类名(const 类名 &);

       2.何时调用复制构造函数:

    将新对象显式地初始化为现有对象:

          stringbad ditto(motto);

          stringbad  metoo = motto;

          stringbad also = stringbad(motto) ;

          stringbad *pstingbad = new stringbad(motto);

     2.函数按值传递或函数返回对象时:(按值传递意味着创建副本)

         void callme2(stringbad sb)

         {...};

        3.默认的复制构造函数的功能:逐个复制静态成员的值,称为浅复制

        stringbad sailor = sports;

        即:

       stringbad sailor;

       sailor.str = sports.str; 

       sailor.len = sports.len;

//这里不是复制字符串,而是复制一个指向这个字符串的指针,得到的是两个指向同一个字符串的指针,当一个指针释放内存时,另一个所指向的内容也被改变,因此会出现错误。

可以改成深度复制:

stringbad::stringbad(const stringbad & st)

{

    num_strings++;

    len = str.len;

    str  = new char [len+1];

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

}

赋值运算符:

stringbad knot;

knot = headline1;    //这才是赋值,不是初始化;

stringbad knot = heandline1;  //这是初始化,不一定会用到赋值运算符;

同样会有上述浅复制的问题,可以编写赋值运算符:

原型:类名 & 类名::operator=(const 类名 &);

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

{

        if (this = &st)

                return *this;

        delete [ ] str;

        len = str.len;

        str = new char [len+1];

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

        return *this;

}

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5713841.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存