C++学习随笔(四)

2020-05-06  本文已影响0人  宇宙巨炮

未经本人授权,禁止转载


这一部分会详细谈谈类


1. include" "与include< >的区别

include" "编译器首先查找当前工作的目录或源代码目录;
include< >编译器首先在存储标准头文件的主机系统的文件系统中查找。

2. 预处理器编译指令#ifndef

以前没有预处理过include"test.h"时才执行中间的代码,可以很好的防止重复引用头文件。

#ifndef TEST_H_
#define  TEST_H_
//...............
#endif

3. 类的构造函数

直接上代码比较直观,以下面的类为例。

class test
{
private:
    int num;
    string str;
public:
    void func();
};
1. 没有构造函数编译器会隐式的声明一个默认构造函数

test x;此时x中的num和str会被创建,但是没有任何值

2. 自己给出构造函数时,编译器不再隐式的声明默认构造函数
test(int t_num , const string & t_str);    //在类内部声明

test::test(int t_num , const string & t_str)    //定义,构造函数没有返回值
{
    num = t_num;
    str = t_str;
}

int main()
{
    test x(12 , "hello world");
    test y = test(12 , "hello world");    //两种完全等价,上面的是隐式调用,下面的是显式调用
    test x;    //!!!报错!!!因为没有了默认构造函数!!!
}

自定义了构造函数但是没有自行提供默认构造函数test x;就会报错,定义默认构造函数有两种方法:

//1. 给构造函数的所有参数提供默认值
test::test(int t_num = 0 , const string & t_str = “err”) 
{
    num = t_num;
    str = t_str;
}

//2. 使用函数重载来定义另一个构造函数——没有任何参数的构造函数
test::test() 
{
    num = 0;
    str = "null";
}
3. 在使用初始化列表初始化类对象时,只要与某个构造函数的参数列表匹配即可
4. 构造函数的初始化列表语法
class example
{
private:
    int x;
    strinh str;
public:
    example(int _x , const string & _str);
};

example::example(int _x , const string & _str) : x(_x) , str(_str) { }    //个人觉得这样很装逼
5. 在构造函数中new的变量必须在析构函数中delete
6. 返回对象会调用复制构造函数,返回引用不会

4. 析构函数详解

最好是给出一个显式的析构函数,如果没有编译器将隐式的声明一个析构函数。

class test
{
private:
    int num;
    string str;
public:
    test();
    test(int t_num , const string & t_str); 
    ~test();    
    void func();
};

析构函数的调用:如果是静态存储类对象,在程序结束时自动调用;如果是自动存储类对象,在代码块{ }结束时自动调用;如果是new的对象,在delete时自动调用。最好不要主动调用析构函数!!!

5. const成员函数

当成员函数不修改任何成员变量时,就应该把它定义为const成员函数以保证函数不会修改调用对象。

void func() const;

void test::func() const
{
    //...........
}

6. this指针

this是一个指向调用对象本身的指针,*this是调用对象本身,注意二者的区别

7. 运算符重载

代码格式:operate运算符(),运算符必须是C++寓言已有的运算符。

class Test
{
private:
    int x;
public:
    Test(int _x = 0);
    Test operate+(const Test & t);
};

Test::Test( int _x = 0)
{
    x = _x;
}

Test Test::operate+(const Test & t)
{
    Test sum;
    sum.x = x + t.x;
    return Test;
}

int main()
{
    Test a(10);
    Test b(20);
    Test c;
    c = a + b;    //等效于c = a.operate+(b);
}

运算符重载的限制:
1.重载后的运算符必须至少有一个操作数是用户自定义的类型
2.使用运算符不能违反原来的句法规则,不能修改运算符的优先级
3.sizeof ,. ,.* ,:: ,?:等运算符不能重载
4.=,(),[],->只能在成员函数中重载

8. 友元函数

可以获得访问类成员权限的函数。

class Test
{
private:
    int x;
public:
    friend int func();    //在类中声明
};

int func()    //定义与普通函数一样,不需要加限定符Test::
{
    return 1;
}

func不是成员函数但是却有成员函数的权限,调用的时候也不是用成员运算符,而是和普通函数一样。

9. 类中的static

在类的成员变量前加上静态声明static,意味着不管创建多少类对象,他们都共同分享这个静态成员变量。

10. 隐式复制构造函数的危害

当构造函数中有new的变量时,最好给出显式的复制构造函数和重载一个复制运算符,因为隐式构造函数是浅复制,这会导致在析构函数被调用时容易出现问题。

上一篇下一篇

猜你喜欢

热点阅读