• c++入门之类与内存


    类作为c++编程的核心,自然我们十分关注其内存分配问题。

    这里的这个主题中,我们关注了静态成员,new,delete.还有构造函数和析构函数。

    先上代码:

     1 # include "iostream"
     2 # ifndef STRNGBAD_H_
     3 # define STRNGBAD_H_
     4 class StringBad
     5 {
     6 private:
     7     char *str;
     8     int len;
     9     static int num_strings; //= 0;//可见除了const 量之外,类内部成员是不能在内部赋初值的
    10 public:
    11     StringBad(const char * s);
    12     StringBad();
    13     ~StringBad();
    14 
    15     friend std::ostream & operator<<(std::ostream & os, const StringBad & st);
    16 };
    17 # endif

    这个类声明十分的简洁,我们可以看到,其只有三个成员变量,成员函数也只要构造函数和析构函数,再包含一个友元函数(我们再次强调:友元函数虽然声明在public中,但并不包含在类作用域中)关注一下第 9 行,这里声明了一个静态变量。关于静态变量。需要知道:静态变量只提供一个副本,实际上在内存中只占用一个空间,即就算我们申请了10个StringBad对象,这10个对象本质上会共享1个num_strings变量。

    再来看,这个类的定义函数:

    # include "cstring"
    # include "strngbad.h"
    
    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 created
    ";
    }
    
    StringBad::StringBad()
    {
        len = 4;
        str = new char[4];
        std::strcpy(str, "C++");
        num_strings++;
        cout << num_strings << ": "" << str << "" default created
    ";
    }
    
    StringBad::~StringBad()
    {
        cout << """ << str << "" object created. ";
        --num_strings;
        cout << num_strings << "left
    ";
        delete[] str;
    }
    
    std::ostream & operator<<(std::ostream & os, const StringBad & st)
    {
        os << st.str;//注意这里打印的是 str,如果不加str呢
        return os;
    }

    我们可以从这个类定义中中,看到静态变量num_strings的作用:统计声明当前作用域中,类对象的个数,当对象产生和销毁的时候,对其动态跟踪。同时,我们注意到:

    这个程序使用的c字符串的痕迹很明显(要逐渐体会c风格字符串有何缺陷)。

    构造函数中使用了new来动态分配内存,析构函数中使用了delete来释放内存。(要注意new和delete的兼容性,即new使用new[],则delete也应使用delete[])。

    下面给出调用该类的代码:

     1 # include "iostream"
     2 using std::cout;
     3 # include "strngbad.h"
     4 
     5 void callme1(StringBad &);
     6 void callme2(StringBad);
     7 
     8 int main()
     9 {
    10     using std::endl;
    11     {
    12         cout << "Starting an inner block.
    ";
    13         StringBad headline1("hello world!");
    14         StringBad headline2("learning forever!");
    15         StringBad sports("i love trvaling!");
    16         cout << "headline1" << headline1 << endl;
    17         cout << "headline12"<< headline2 << endl;
    18         cout << "sports" << sports << endl;
    19         callme1(headline1);
    20         cout << "headline1" << headline1 << endl;
    21         callme2(headline2);
    22         cout << "headline2" << headline2 << endl;
    23         cout << "Initialize one object to another:
    ";
    24         StringBad sailor = sports;
    25         cout << "sailor: " << sailor << endl;
    26     }
    27     cout << "End of main()
    ";
    28     system("pause");
    29     return 0;
    30 }
    31 
    32 void callme1(StringBad & rsb)
    33 {
    34     cout << "String passed by reference:
    ";
    35     cout << "     
    " << rsb << ""
    ";
    36 }
    37 
    38 void callme2(StringBad  sb)
    39 {
    40     cout << "String passed by rvalue:
    ";
    41     cout << "     
    " << sb << ""
    ";
    42 }

    这里先讨论32行和38行:将对象值作为形参和 对象引用作为形参,到底有何区别?

    首先需要明白:当采用按值传递参数的时候,会首先复制原来的类对象,当然,也不是简单的复制。这个复制过程很特殊。比如,我们将这个临时变量定义为A,则将对象B的值传递给函数的时候。过程是:A = B, 更具体的讲,是:A =StringBad(B),这个会发生什么呢,当然是,首先调用构造函数,但很可惜的是,这里的构造函数不是我们定义的构造函数,而是编译器生成的构造函数,因此也没有new这一过程,但是当函数执行完。(意味着函数作用域结束),则意味着要调用析构函数了,而这个析构函数却是我们自己的析构函数。,这是极其容易出错的!!!!

  • 相关阅读:
    构造代码块重要理解
    Java中静态代码块、构造代码块、构造函数、普通代码块
    MySQL-分组查询(GROUP BY)及二次筛选(HAVING)
    mysql select将多个字段横向合拼到一个字段
    java语言支持的变量类型
    static修饰属性,方法,类
    恶意代码分析----网络环境配置
    Windows反调试技术(下)
    Windows反调试技术(上)
    脱壳入门----常见的寻找OEP的方法
  • 原文地址:https://www.cnblogs.com/shaonianpi/p/9955192.html
Copyright © 2020-2023  润新知