C++自学-《北京大学精品课》笔记

1、引用
(1)某个变量的引用,等价于这个变量,相当于该变量的一个别名
(2)定义引用时一定要将其初始化成引用某个变量
(3)初始化后,它就一直引用该变量,不会再引用别的变量了
(4)引用只能引用变量,不能引用常量和表达式
(5)常引用:定义引用时,前面加const关键字,即为“常引用”
(6)不能通过常引用去修改其引用的内容

2、const关键字
(1)不可通过常量指针修改其指向的内容
(2)不能把常量指针赋值给非常量指针,反过来可以
(3)函数参数为常量指针时,可避免函数内部不小心改变参数指针所指地方的内容
(4)不能通过常引用修改其引用的变量

3、动态内存分配
new运算符:
(1)第一种用法,分配一个变量: P = new T (T是任意变量名,P是类型为T *的指针)
(2)第二种用法,分配一个数组: P = new T[N] (T是任意变量名,P是类型为T *的指针,N是要分配的数组元素的个数,可以是整型表达式)
(3)new运算符的返回值类型是 T *
delete运算符:
(1)用new动态分配的内存空间,一定要用delete运算符进行释放: delete 指针,一片空间不能被delete多次
(2)用delete释放动态分配的数组,要加[]:delete[]指针 // 该指针必须指向new出来的数组

4、内联函数
(1)在函数定义前面加“inline”关键字,即可定义内联函数

5、函数重载
(1)一个或多个函数,名字相同,然而参数个数或参数类型不相同,这叫做函数的重载
(2)编译器根据调用语句中的实参的个数和类型判断应该调用哪个函数

6、函数的缺省参数
(1)C++中,定义函数的时候可以让最右边的连续若干个参数有缺省值,那么调用函数的时候,若相应位置不写参数,参数就是缺省值

void func(int x1, int x2 = 2, int x3 = 3) { }
func(10); // 等效于func(10, 2, 3)
func(10,8); // 等效于func(10, 8, 3)
func(10, ,8); //不行,只能最右边的连续若干个参数缺省

(2)函数参数可缺省的目的在于提高程序的可扩充性,即如果某个写好的函数要添加新的参数,而原先那些调用该函数的语句,未必需要使用新增的参数,
那么为了避免对原先那些函数调用语句的修改,就可以使用缺省参数

7、类和对象的基本概念
(1)类的成员函数和类的定义分开写: 如int CRectangle::Area() CRectangle:: 说明后面的函数是CRectangle类的成员函数,而非普通函数。那么,一定
要通过对象或对象的指针或对象的引用才能调用
(2)类成员的可访问范围:在类的定义中,用下列访问范围关键字来说明类成员可被访问的范围:

    private: 私有成员,只能在成员函数内访问
    pubilc: 公有成员,可以在任何地方访问
    protected: 保护成员,

如果某个成员前面没有关键字,则缺省地被认为是私有成员
(3)成员函数也可以重载
(4)成员函数也可以带缺省参数

8、构造函数(construct)
(1)成员函数的一种,可以有参数但是不能有返回值(void)都不行
(2)作用是对对象进行初始化,如给成员变量赋初值
(3)如果定义类时没写构造函数,则编译器自动生成一个默认的无参数的构造函数
(4)一个类可以有多个构造函数(函数重载)

class Complex {
    private: 
        double real, imag;
    public:
        Complex(double r, double i = 0);
};
Complex::Complex(double r, double i) {
    real = r; imag = i;
}
Complex c1; // error, 缺少构造函数的参数
Complex * pc = new Complex; // error,没有参数
Complex c1(2); // OK
Complex * pc = new Complex(3,4);

class Complex {
    private:
        double real, imag;
    public:
        void Set(double r, double i);
        Complex(double r, double i);
        Complex(double r);
        Complex(Complex c1, Complex c2);
};
Complex::Complex(double r, double i)
{
    real = r; imag = i;
}
Complex::Complex(double r)
{
    real = r; imag = 0;
}
Complex::Complex(Complex c1, Complex c2)
{
    real = c1.real + c2.real;
    imag = c1.imag + c2.imag;
}
Complex c1(3), c2(1,0), c3(c1, c2);

构造函数在数组中的使用:

class CSample {
    int x;
public:
    CSample() {
        cout << "****" << endl;
    }
    CSample(int n) {
        cout << "&&&&&" << endl;
    }
};

有参数就输出**** 没有参数就输出&&&&&

class Test {
public:
    Test(int n) { }
    Test(int n, int m) { }
    Test() { };
};
Test array1[3] = {1, Test(1,2) };
Test attay2[3] = {Test(2,3), Test(1,2), 1};
Test * pArray[3] = {new Test(4), new Test(1, 2) }; // 只生成了两个对象, pArray[2]没有初始化,我们并不知道它指向哪,所以不会生成对象


9、复制构造函数
(1)只有一个参数,即对同类对象的引用, 注意参数必须是引用 不允许出现如: X::X(X)的构造函数
(2)形如: X::X( X&) 或 X::X(const X&), 二者选一, 后者能以常量对象作为参数
(3)如果没有定义复制构造函数,那么编译器生成默认复制构造函数。默认的复制构造函数完成复制功能。
默认复制构造函数:

class Complex {
private:
double real, imag;
};
Complex c1; // 调用缺省无参构造函数
Complex c2(c1); // 调用缺省的复制构造函数,将c2初始化成和c1一样

自己定义的复制构造函数:

class Complex {
    public:
        double real, imag;
    Complex() {};
    Complex(const Complex & c) {
        real = c.real;
        imag = c.imag;    
    }
};
Complex c1;
Complex c2(c1);

4)复制构造函数起作用的三种情况:
  1.当用一个对象去初始化同类的另一个对象时

    Complex c2(c1);
    Complex c2 = c1;   // 另外一种写法,不是赋值,是初始化

  2.如果某函数有一个参数是类A的对象,那么该函数被调用时,类A的复制构造函数将被调用

class A
    {
        public:
        A() {};
        A(A&a) {
        cout << "*****" << endl;
        }
    };
    void Func(A a1) {}
    int main() {
        A a2;
        Func(a2);
        return 0;
    }

【疑惑】3.如果函数的返回值是类A的对象时,则函数返回时,A的复制构造函数被调用

    class A
    {
        public:
        int v;
        A(int n) { v = n;};
        A(const A & a) {
            v = a.v;
            cout << "Copy construct called" << endl;
        }
    };
    A func() {
        A b(4);
        return b;
    }
    int main() {
        cout << func().v << endl; 
        return 0;
    }
    输出结果是:
    Copy construct called
    4

注意:对象间赋值并不导致复制构造函数被调用

常量引用参数的使用:

void fun(CMyclass obj_) {
    cout << "fun" << endl;
}

这样的函数,调用时生成形参会引发复制构造函数调用,开销比较大
所以可以考虑使用CMyclass & 引用类型作为参数
如果希望确保实参的值在函数中不应被改变,那么可以加上const关键字:

void fun(const CMyclass & obj) {
    // 函数中任何试图改变obj值的语句都将变成非法的
}

 

上一篇:Spring Cloud Gateway 没有链路信息,我 TM 人傻了(下)


下一篇:Java反射使用