C++学习笔记(自己用的)

C++学习笔记(自己用的),第1张

C++ 学习笔记 C++基础(一些细节)
  1. C++ 中使用 cout 输出 bool 变量的值时还是用数字 1 和 0 表示,而不是 true 或 false。(C++ 中 非0即1(只用数值0/false是0,其他全是1))

  2. new 和 delete、new[] 和 delete[] *** 作符应该成对出现,并且不要和C语言中 malloc()、free() 一起混用。

  3. 为了消除函数调用的时空开销,C++ 提供一种提高效率的方法,即在编译时将函数调用处用函数体替换,类似于C语言中的宏展开。这种在函数调用处直接嵌入函数体的函数称为内联函数(Inline Function),又称内嵌函数或者内置函数。(在函数前加上关键字 inline 即可(要在函数定义处添加 inline 关键字,在函数声明处添加 inline 关键字虽然没有错,但这种做法是无效的,编译器会忽略函数声明处的 inline 关键字。))

  4. 当函数比较复杂时,函数调用的时空开销可以忽略,大部分的 CPU 时间都会花费在执行函数体代码上,所以我们一般是将非常短小的函数声明为内联函数。

  5. C++规定,默认参数只能放在形参列表的最后,而且一旦为某个形参指定了默认值,那么它后面的所有形参都必须有默认值。实参和形参的传值是从左到右依次匹配的,默认参数的连续性是保证正确传参的前提。

// 正确
void func(int a, int b=10, int c=20){ }
void func(int a, int b, int c=20){ }
// 错误
void func(int a, int b=10, int c=20, int d){ }
void func(int a, int b=10, int c, int d=20){ }
  1. 参数列表又叫参数签名,包括参数的类型、参数的个数和参数的顺序,只要有一个不同就叫做参数列表不同。
  2. 类名的首字母一般大写,以和其他的标识符区分开。{ }内部是类所包含的成员变量和成员函数,它们统称为类的成员
class Student{
public:
    //成员变量
    char *name;
    int age;
    float score;
    //成员函数
    void say(){
        cout<<name<<"的年龄是"<<age<<",成绩是"<<score<<endl;
    }
};

Student liLei;  //创建对象
  1. 两种创建对象的方式:一种是在栈上创建,形式和定义普通变量类似;另外一种是在堆上使用 new 关键字创建,必须要用一个指针指向它,读者要记得 delete 掉不再使用的对象。
  2. 对象名字访问成员使用点号.,通过对象指针访问成员使用箭头->,这和结构体非常类似。
//创建对象
    Student stu;
    stu.name = "小明";
    stu.age = 15;
    stu.score = 92.5f;
    stu.say();

	Student *pStu = new Student;
    pStu -> name = "小明";
    pStu -> age = 15;
    pStu -> score = 92.5f;
    pStu -> say();
    delete pStu;  //删除对象

  1. 也可以只在类体中声明函数,而将函数定义放在类体外面(::被称为域解析符(也称作用域运算符或作用域限定符),用来连接类名和函数名,指明当前函数属于哪个类)(成员函数必须先在类体中作原型声明,然后在类外定义,也就是说类体的位置应在函数定义之前。)
class Student{
public:
    //成员变量
    char *name;
    int age;
    float score;
    //成员函数
    void say();  //函数声明
};
//函数定义
void Student::say(){
    cout<<name<<"的年龄是"<<age<<",成绩是"<<score<<endl;
}
  1. 在类体中和类体外定义成员函数是有区别的:在类体中定义的成员函数会自动成为内联函数,在类体外定义的不会。当然,在类体内部定义的函数也可以加 inline 关键字,但这是多余的,因为类体内部定义的函数默认就是内联函数。
  2. 内联函数一般不是我们所期望的,它会将函数调用处用函数体替代,所以我建议在类体内部对成员函数作声明,而在类体外部进行定义,这是一种良好的编程习惯,实际开发中大家也是这样做的。当然,如果你的函数比较短小,希望定义为内联函数,那也没有什么不妥的。
  3. 类函数定义在外部也可以是内联函数
class Student{
public:
    char *name;
    int age;
    float score;
    void say();  //内联函数声明,可以增加 inline 关键字,但编译器会忽略
};
//函数定义
inline void Student::say(){
    cout<<name<<"的年龄是"<<age<<",成绩是"<<score<<endl;
}
  1. 构造函数在实际开发中会大量使用,它往往用来做一些初始化工作,例如对成员变量赋值、预先打开文件等。
  2. 调用没有参数的构造函数也可以省略括号
  3. VLA 类包含了两个成员变量,m_len 和 m_arr 指针,需要注意的是 m_len 加了 const 修饰,只能使用初始化列表的方式赋值
class VLA{
private:
    const int m_len;
    int *m_arr;
public:
    VLA(int len);
};
//必须使用初始化列表来初始化 m_len
VLA::VLA(int len): m_len(len){
    m_arr = new int[len];
}

17.如下赋值是错误的

class VLA{
private:
    const int m_len;
    int *m_arr;
public:
    VLA(int len);
};
VLA::VLA(int len){
    m_len = len;
    m_arr = new int[len];
}
  1. 上面我们定义了一个 VLA 类来模拟变长数组,它使用一个构造函数为数组分配内存,这些内存在数组被销毁后不会自动释放,所以非常有必要再添加一个析构函数,专门用来释放已经分配的内存。请看下面的完整示例:
#include 
using namespace std;
class VLA{
public:
    VLA(int len);  //构造函数
    ~VLA();  //析构函数
public:
    void input();  //从控制台输入数组元素
    void show();  //显示数组元素
private:
    int *at(int i);  //获取第i个元素的指针
private:
    const int m_len;  //数组长度
    int *m_arr; //数组指针
    int *m_p;  //指向数组第i个元素的指针
};
VLA::VLA(int len): m_len(len){  //使用初始化列表来给 m_len 赋值
    if(len > 0){ m_arr = new int[len];  /*分配内存*/ }
    else{ m_arr = NULL; }
}
VLA::~VLA(){
    delete[] m_arr;  //释放内存
}
void VLA::input(){
    for(int i=0; m_p=at(i); i++){ cin>>*at(i); }
}
void VLA::show(){
    for(int i=0; m_p=at(i); i++){
        if(i == m_len - 1){ cout<<*at(i)<<endl; }
        else{ cout<<*at(i)<<", "; }
    }
}
int * VLA::at(int i){
    if(!m_arr || i<0 || i>=m_len){ return NULL; }
    else{ return m_arr + i; }
}
int main(){
    //创建一个有n个元素的数组(对象)
    int n;
    cout<<"Input array length: ";
    cin>>n;
    VLA *parr = new VLA(n);
    //输入数组元素
    cout<<"Input "<<n<<" numbers: ";
    parr -> input();
    //输出数组元素
    cout<<"Elements: ";
    parr -> show();
    //删除数组(对象)
    delete parr;
    return 0;
}
  1. 一个类中可以有一个或多个静态成员变量,所有的对象都共享这些静态成员变量,都可以引用它。
class Student{
public:
    Student(char *name, int age, float score);
    void show();
public:
    static int m_total;  //静态成员变量
private:
    char *m_name;
    int m_age;
    float m_score;
};
/通过类类访问 static 成员变量
Student::m_total = 10;
//通过对象来访问 static 成员变量
Student stu("小明", 15, 92.5f);
stu.m_total = 20;
//通过对象指针来访问 static 成员变量
Student *pstu = new Student("李华", 16, 96);
pstu -> m_total = 20;
  1. static 成员变量和普通 static 变量一样,都在内存分区中的全局数据区分配内存,到程序结束时才释放。这就意味着,static 成员变量不随对象的创建而分配内存,也不随对象的销毁而释放内存。而普通成员变量在对象创建时分配内存,在对象销毁时释放内存。
  2. 静态成员变量必须初始化,而且只能在类体外进行。例如:
int Student::m_total = 10;

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

原文地址: http://outofmemory.cn/langs/3002799.html

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

发表评论

登录后才能评论

评论列表(0条)

保存