一、c和c++中const的区别

C语言:加const

  1. 生成的是全局的符号;
  2. const修饰的是变量(是一个常属性的变量);

C++:加const

  1. 不生成符号,在编译阶段直接对初始化时值进行替换(常量);
  2. 作用域是本文件;
  3. 必须初始化,且后面无法修改;

二、c和c++堆区开辟二维数组

C语言:malloc、free

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
//一维数组:
int *arr = (int*)malloc(sizeof(int) * 10);
assert(arr != NULL);
free(arr);

//二维数组:10 * 20
int** ApplySecondArr()
{
int **brr = (int *)malloc(10 * sizeof(int *));
assert(NULL != brr);

for(int i = 0; i < 10; i++)
{
brr[i] = (int *)malloc(sizeof(int) * 20);
if(brr[i] == NULL)
{
printf("error\n");
return NULL;
}

}
return brr;
}

void FreeSpace(int** brr, int rows)
{
//释放
if(brr != NULL)
{
//先删除后申请的
for(int i = 0; i < rows; i++)
{
if(brr[i] != NULL)
{
free(brr[i]);
brr[i] = NULL;
}

}
free(brr);
brr = NULL;
}
}

c++:new、delete

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//一维数组:	
const int len = 10;
//创建:申请不用判空,自动抛异常
int *err = new int[len];
//释放
if(NULL != err)
{
delete[] err;
}

//二维数组:
int main()
{
//申请2*10个int类型的空间
int** arr = new int* [2];
for (int i = 0; i < 2; i++)
{
arr[i] = new int[10];
}

//释放
for (int i = 0; i < 2; i++)
{
delete[] arr[i];
}
delete[] arr;
}

三、关于using namespace std;

using 、namespace 都是c++的关键字

namespace是命名空间,std就是空间名

作用:解决命名冲突,不同命名空间下的同名变量、方法、类、结构体等不会产生冲突

下面举个例子:自己定义一个命名空间

fun.h文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
using namespace std;
namespace hello
{
void fun()
{
cout << "hello,world" <<endl;
}
}
namespace cpp
{
void fun()
{
cout << "cpp"<< endl;
}
}

main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include "fun.h"

//方式一:直接全局声明在本文件可使用hello命名空间的内容
using namespace hello;

int main()
{
fun();
//此时fun()函数使用的是hello命名空间下的fun()函数
//结果:hello,world


//方式二:命名空间名::方法
cpp::fun();
//结果:cpp
return 0;
}

注意:

  1. 命名空间只能在全局定义

  2. 命名空间可以嵌套命名空间

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    namespace a
    {
    int ma = 10;
    namespace b
    {
    int ma = 20;
    }
    }

    //访问
    //a::的ma = 10
    cout << a::ma << end;

    //a::b::ma = 20;
    cout << a::b::ma<< endl;
  1. 命名空间名可以是匿名

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    namespace
    {
    int ma = 10;
    int mb = 20;
    }

    //访问
    cout << ma << endl;
    cout << ::ma << endl;

  2. 同名命名空间可以进行合并(相当于补充的功能)

  3. 命名空间名可以起别名

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    namespace oldname
    {
    int ma = 10;
    }

    void test()
    {
    namespace newname = oldname;
    cout << newname::ma << endl;
    }

四、为什么使用初始化列表

初始化列表使用情况:只有构造函数才有初始化列表;对成员属性进行初始化

以下情况均需要在初始化列表进行初始化(常变量、引用)。

原因:成员属性中的常变量、引用在调用构造函数test()之前就需要进行初始化,所以只能使用初始化列表进行初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iosream>

class test
{
public:
test(int a, int b)
:ma(a),mb(b)
{
}
private:
const int ma;
int &mb;
};

五、关于this指针

this指针:是隐含在每一个非静态成员函数的指针;
本质:Person const this ;可以改变指向的内容,不可以改变指向;
用途:
1.当形参与成员变量名相同时,可用this指针加以区分;
2.在类的非静态成员函数中返回类的对象的本身,可使用return
this;

六、成员变量和成员函数的联系

  1. 成员变量和成员函数是分开存储的

  2. 当类是一个空类时,该类实例化的对象的大小是1字节;
    这是编译器为了区分空对象的占用内存的地址;

  3. 非静态成员变量 属于类的对象;
    静态成员变量 不属于类的对象上;
    静态成员函数 不属于类的对象上;
    非静态成员函数 不属于类的对象上;

七、函数指针调用成员方法

函数指针:typedef void (*pfun)();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
using namespace std;
class test
{
public:
test():ma(0)
{}
test(int a)
{
ma = a;
}
void Show()
{
cout <<this->ma << endl;
}
private:

int ma;
};
int main()
{
typedef void (test::*pshow)();
//函数指针p指向test类中的Show方法
pshow p = &test::Show;

//使用 (对象.*p)()调用test::Show()方法
test ts;
(ts.*p)();
test* pts = new test(20);
(pts->*p)();
return 0;
}

八、使用typeid(类、对象、变量名、函数).name()函数

c++可以查看类型

1
2
3
4
5
6
7
8
9
#include <iostream>
#include <typeinfo>
using namespace std;
int main()
{
int a = 10;
cout <<typeid(a).name() << endl;
return 0;
}

九、函数返回值怎么被带回调用方

在32位系统上(非类类型),根据返回值的字节大小来不同的返回方式:

  • sizeof(data) <= 4字节 由ax寄存器把数据保存起来
  • sizeof(data) > 4 && sizeof(data) <= 8 由ax、dx寄存器把数据保存起来
  • sizeof(data) > 8 时,由寄存器存放临时量的地址,返回临时量的地址

类类型:

不管几个字节,都是由寄存器带回临时对象的地址

十、c/c++函数调用约定

_cdcel:c标准默认调用约定

_stdcall:windows下的调用约定

_fastcall:快速调用约定

约束内容:

  1. 生成的符号:不同调用约定的函数不能调用

  2. 入栈的顺序:c/c++都是从右向左sum(a, b),先b后a

  3. 开辟、清理 形参的内存:

    1. _cdecl 调用方开辟、清理;

    2. _stdcall调用方开辟、被调用清理;

    3. _fastcall;前两个形参由寄存器带入被调用方,没有内存开辟

      ​ 以后的形参都是_stdcall相同的调用约定

十一、静态成员函数、静态成员属性

特点:
所有的对象共享一份数据;
在编译阶段给分配内存;
类内声明,类外初始化

访问:
使用对象调用;
使用类名调用;

静态成员属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Preson
{
public :
void SetAge(int age)
{
m_age = age;
}
private:

static int m_age;

};
//类外初始化:需加上作用域
int Person::m_age = 18;

静态成员函数:

  • 静态成员函数可以访问静态成员变量;

  • 静态成员函数不可以访问非静态成员变量;

    注意:通过类名访问成员函数时,只能访问静态成员函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    class test
    {
    public:
    static void show()
    {
    cout << ma << endl;
    }
    private:
    static int ma;
    };
    //类外初始化
    int test::ma = 10;

    int main()
    {
    //对象调用
    test ts;
    ts.show();
    //类名调用
    test::show();
    return 0;
    }

十二、空指针 this访问成员函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class test
{
public:
void Showma()
{
cout << ma << endl;
}
void ShowHello()
{
cout << "hello,world" << endl;
}
private:
int ma;
};

int main()
{
test* pts = NULL;
//err
//pts->Showma();

//成功
pts->ShowHello();
return 0;
}

结果:空指针test* pts = NULL

访问成员函数的两种结果:

  1. 访问成功:不包含成员属性的成员函数pts->ShowHello()
  2. 访问失败:包含成员属性的成员函数pts->Showma()

十三、extern C

十四、类与类之间的关系及构造、析构顺序

依赖、关联、聚合、组合、继承

十五、函数模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//<>不仅能存放模板的类型参数、非类型的整形int常量(float、double不行)
template<typename T, int LEN> //LEN是常量
void ShowArr(T* arr)
{
for (int i = 0; i < LEN; i++)
{
cout << arr[i] <<" ";
}
cout << endl;
}

int main()
{
int arr[10] = { 1, 2 };
ShowArr<int, 2>(arr);
}

注意:模板并不是万能的,比如自定义类型

所以就有了模板的特例化:

调用优先级:

普通函数 >特例化模板函数 > 模板函数

十六、类模板

1
2
3
4
5
6
template<class T>
class demon
{
public:
T value;
};

两种特例化的方式:

  1. 完全特例化:类、函数都可以
  2. 部分特例化:只有类的成员方法

typename 作用:

  1. 定义模板参数
  2. 指明模板的类型