1.字符串
(1)C++中每个字符串都以字符'\0'作为结尾。
(2)一个char类型占用一个字节;int类型占用4个字节;一个指针在32位系统上占用4个字节,在64位系统上占用8个字节。NULL空指针也占4或8个字节。
(3)定义一个字符串:char str[] = "abcd";,此时strlen(str)=4,sizeof(str)=5,因为sizeof求得的是占用的字节数,因此包含了结尾符号;而strlen求得的是字符串的长度,不包括最后的结尾符。因此str2=""空字符串的sizeof是1,strlen是0.
strlen的头文件是#include <string.h>
(4)string 类型的对象中末尾不会自动加'\0'字符,字符串中间可以存在'\0';string str,则不论str多长,sizeof(str)=sizeof(string)=32
(5)
2.指针和引用
https://blog.youkuaiyun.com/qq_27678917/article/details/70224813
3.数组
(1)int data[] = {1,2,3,4,5};int mat[3][3] = {1,2,3,4,5,6,7,8,9};此时sizeof(data)等于20.
(2)数组作为函数参数时,多维数组的除了第一维之外都要写明大小。如:int fun(int data[]) 和 int fun(int mat[][3]).
(3)当数组作为函数的参数进行传递时,数组会自动退化为同类型的指针,此时sizeof的结果为sizeof(指针)=4/8;
(4)动态数组:int *p = new int;//默认初始化;int *p = new int();//值初始化;int *p = new int(0);
(5)string *p = new string[2];//p指向一个大小为2的数组,数组元素的类型是string,此时sizeof(p)=8,sizeof(*p)=32;
4.公有继承和私有继承
在继承时:
1、不管采用哪种形式(public, protected或private),基类中的私有成员都不可以被继承;如果非要在派生类中使用基类的私有成员,可以有两种方法:一是使用属性,二是使用友元类或友元函数。
2、如果采用public形式,则基类除了私有成员的其它所有都被原样的继承到派生类中;即在基类中是public的,在派生类中还是public的,在基类中是protected的,在派生类中还是protected的。
3、如果采用protected形式,则基类中除了私有成员的其它所有都被以protected的形式继承到派生类中。
C++中的继承方式有:
public、private、protected三种(它们直接影响到派生类的成员、及其对象对基类成员访问的规则)。
(1)public(公有继承):继承时保持基类中各成员属性不变,并且基类中private成员被隐藏。派生类的成员只能访问基类中的public/protected成员,而不能访问private成员;派生类的对象只能访问基类中的public成员。
(2)private(私有继承):继承时基类中各成员属性均变为private,并且基类中private成员被隐藏。派生类的成员也只能访问基类中的public/protected成员,而不能访问private成员;派生类的对象不能访问基类中的任何的成员。
(3)protected(保护性继承):继承时基类中各成员属性均变为protected,并且基类中private成员被隐藏。派生类的成员只能访问基类中的public/protected成员,而不能访问private成员;派生类的对象不能访问基类中的任何的成员。
5.静态变量
1、静态变量在内存的静态存储区,静态数据一直占有着该存储区单元直到程序结束;
2、静态局部变量只声明一次,一旦申请内存成功,不再接受重复申请;
3、静态局部变量的作用域与一般局部变量一样,二者区别在于以上两点:一般局部变量在函数调用结束后释放变量占用的存储单元,而静态局部变量不释放,直到程序结束才释放。函数中的静态变量是静态局部变量 函数退出后不被释放,在程序运行结束时才释放。只在函数中可访问。
4、静态全局变量的作用域只能是定义它的文件里,不是被其他文件使用。
6.数据库
在视图上使用INSERT语句,下列(C)情况可以进行插入操作.
A.视图中包含了使用统计函数的结果
B.视图由多个表连接而成,对多个表的列进行插入操作
C.视图全部包含了基本表中属性为NOT NULL的列
D.视图中使用了DICTINCT
解析:
视图除了进行查询记录外,也可以利用视图进行插入、更新、删除记录的操作,减少对基表中信息的直接操作,提高了数据的安全性。
在视图上使用INSERT语句添加数据时,要符合以下规则。
(1)使用INSERT语句向数据表中插入数据时,用户必须有插入数据的权利。
(2)由于视图只引用表中的部分字段,所以通过视图插入数据时只能明确指定视图中引用的字段的取值。而那些表中并未引用的字段,必须知道在没有指定取值的情况下如何填充数据,因此视图中未引用的字段必须具备下列条件之一。
该字段允许空值。
该字段设有默认值。
该字段是标识字段,可根据标识种子和标识增量自动填充数据。
该字段的数据类型为timestamp或uniqueidentifier。
(3)视图中不能包含多个字段值的组合,或者包含使用统计函数的结果。
(4)视图中不能包含DISTINCT或GROUP BY子句。
(5)如果视图中使用了WITH CHECK OPTION,那么该子句将检查插入的数据是否符合视图定义中SELECT语句所设置的条件。如果插入的数据不符合该条件,SQL Server会拒绝插入数据。
(6)不能在一个语句中对多个基础表使用数据修改语句。因此,如果要向一个引用了多个数据表的视图添加数据时,必须使用多个INSERT语句进行添加。
7.C++中的关键字
7.1 const
对于指针类型的不同写法:
const char* p;//p指向的内容是不可变的
char* const p;//p指针本身是不可变的
char const *p;//p指向的内容是不可变的,和第一种含义相同
判断方法:const在*右边,和p紧挨着时,它修饰的是指针;const在*左侧,不和p紧挨着时,它修饰的是指针指向的变量。
const char* const p;//二者都不可变
1.const修饰函数参数
它表示在函数体中不能修改参数的值(包括参数本身的值或者参数其中包含的值):
void function(const int Var);//传递过来的参数在函数内不可以改变(无意义,该函数以传值的方式调用)
void function(const char* Var);//参数指针所指内容为常量不可变
void function(char* const Var);//参数指针本身为常量不可变(也无意义,var本身也是通过传值的形式赋值的)
void function(const Class& Var);//引用参数在函数内不可以改变
参数const通常用于参数为指针或引用的情况,若输入参数采用“值传递”方式,由于函数将自动产生临时变量用于复制该参数,该参数本就不需要保护,所以不用const修饰。
2.const修饰类对象/对象指针/对象引用
const修饰类对象表示该对象为常量对象,其中的任何成员都不能被修改。对于对象指针和对象引用也是一样。
const修饰的对象,该对象的任何非const成员函数都不能被调用,因为任何非const成员函数会有修改成员变量的企图。
例如:
class AAA
{
void func1();
void func2() const;
};
const AAA aObj;
aObj.func1(); 错误
aObj.func2(); 正确
3.const修饰数据成员
const数据成员只在某个对象生存期内是常量,而对于整个类而言却是可变的。因为类可以创建多个对象,不同的对象其const数据成员的值可以不同。所以不能在类声明中初始化const数据成员,因为类的对象未被创建时,编译器不知道const数据成员的值是什么,例如:
class A
{
const int size = 100; //错误
int array[size];//错误,未知的size
}
const数据成员的初始化只能在类的构造函数的初始化列表中进行
4.const修饰成员函数
const修饰类的成员函数,用const修饰的成员函数不能改变对象的成员变量。一般把const写在成员函数的最后:
class A
{
…
void function()const; //常成员函数,它不改变对象的成员变量,也不能调用类中任何非const成员函数。
}
对于const类对象/指针/引用,只能调用类的const成员函数。
5.const修饰成员函数的返回值
通常,不建议用const修饰函数的返回值类型为某个对象或对某个对象引用的情况。原因如下:如果返回const对象,或返回const对象的引用,则返回值具有const属性,返回实例只能访问类A中的公有(保护)数据成员和const成员函数,并且不允许对其进行赋值操作,这在一般情况下很少用到。
6.const常量与define宏定义的区别
(1)编译器处理方式不同
define宏是在预处理阶段展开。
const常量是编译运行阶段使用。
(2)类型和安全检查不同
define宏没有类型,不做任何类型检查,仅仅是展开。
const常量有具体的类型,在编译阶段会执行类型检查。
(3)存储方式不同
define宏仅仅是展开,有多少地方使用,就展开多少次,不会分配内存。
const常量会在内存中分配(可以是堆中也可以是栈中)。
const与#define最大的差别,const在堆栈分配了空间,而#define只是把具体数值 直接传递到目标变量罢了。或者说,const的常量是一个Run-Time的概念,他在程序中确确实实的存在可以被调用、传递。而#define常量则是一个Compile-Time概念,它的生命周期止于编译期:在实际程序中他只是一个常数、一个命令中的参数,没有实际的存在。 const常量存在于程序的数据段。 #define常量存在于程序的代码段。
7.2 static
1. 什么是static?
static 是 C/C++ 中很常用的修饰符,它被用来控制变量的存储方式和可见性。
1.1 static 的引入
我们知道在函数内部定义的变量,当程序执行到它的定义处时,编译器为它在栈上分配空间,函数在栈上分配的空间在此函数执行结束时会释放掉,这样就产生了一个问题: 如果想将函数中此变量的值保存至下一次调用时,如何实现? 最容易想到的方法是定义为全局的变量,但定义一个全局变量有许多缺点,最明显的缺点是破坏了此变量的访问范围(使得在此函数中定义的变量,不仅仅只受此函数控制)。static 关键字则可以很好的解决这个问题。
另外,在 C++ 中,需要一个数据对象为整个类而非某个对象服务,同时又力求不破坏类的封装性,即要求此成员隐藏在类的内部,对外不可见时,可将其定义为静态数据。
1.2 静态数据的存储
全局(静态)存储区:分为 DATA 段和 BSS 段。DATA 段(全局初始化区)存放初始化的全局变量和静态变量;BSS 段(全局未初始化区)存放未初始化的全局变量和静态变量。程序运行结束时自动释放。其中BBS段在程序执行之前会被系统自动清0,所以未初始化的全局变量和静态变量在程序执行之前已经为0。存储在静态数据区的变量会在程序刚开始运行时就完成初始化,也是唯一的一次初始化。
在 C++ 中 static 的内部实现机制:静态数据成员要在程序一开始运行时就必须存在。因为函数在程序运行中被调用,所以静态数据成员不能在任何函数内分配空间和初始化。
这样,它的空间分配有三个可能的地方,一是作为类的外部接口的头文件,那里有类声明;二是类定义的内部实现,那里有类的成员函数定义;三是应用程序的 main() 函数前的全局数据声明和定义处。
静态数据成员要实际地分配空间,故不能在类的声明中定义(只能声明数据成员)。类声明只声明一个类的"尺寸和规格",并不进行实际的内存分配,所以在类声明中写成定义是错误的。它也不能在头文件中类声明的外部定义,因为那会造成在多个使用该类的源文件中,对其重复定义。
static 被引入以告知编译器,将变量存储在程序的静态存储区而非栈上空间,静态数据成员按定义出现的先后顺序依次初始化,注意静态成员嵌套时,要保证所嵌套的成员已经初始化了。消除时的顺序是初始化的反顺序。
优势:可以节省内存,因为它是所有对象所公有的,因此,对多个对象来说,静态数据成员只存储一处,供所有对象共用。静态数据成员的值对每个对象都是一样,但它的值是可以更新的。只要对静态数据成员的值更新一次,保证所有对象存取更新后的相同的值,这样可以提高时间效率。
2. 在 C/C++ 中static的作用
2.1 总的来说
-
(1)在修饰变量的时候,static 修饰的静态局部变量只执行初始化一次,而且延长了局部变量的生命周期,直到程序运行结束以后才释放。
- (2)static 修饰全局变量的时候,这个全局变量只能在本文件中访问,不能在其它文件中访问,即便是 extern 外部声明也不可以。
- (3)static 修饰一个函数,则这个函数的只能在本文件中调用,不能被其他文件调用。static 修饰的变量存放在全局数据区的静态变量区,包括全局静态变量和局部静态变量,都在全局数据区分配内存。初始化的时候自动初始化为 0。
- (4)不想被释放的时候,可以使用static修饰。比如修饰函数中存放在栈空间的数组。如果不想让这个数组在函数调用结束释放可以使用 static 修饰。
- (5)考虑到数据安全性(当程序想要使用全局变量的时候应该先考虑使用 static)。
2.2 静态变量与普通变量
静态全局变量有以下特点:
- (1)静态变量都在全局数据区分配内存,包括后面将要提到的静态局部变量;
- (2)未经初始化的静态全局变量会被程序自动初始化为0(在函数体内声明的自动变量的值是随机的,除非它被显式初始化,而在函数体外被声明的自动变量也会被初始化为 0);
- (3)静态全局变量在声明它的整个文件都是可见的,而在文件之外是不可见的。
优点:静态全局变量不能被其它文件所用;其它文件中可以定义相同名字的变量,不会发生冲突。
(1)全局变量和全局静态变量的区别
- 1)全局变量是不显式用 static 修饰的全局变量,全局变量默认是有外部链接性的,作用域是整个工程,在一个文件内定义的全局变量,在另一个文件中,通过 extern 全局变量名的声明,就可以使用全局变量。
- 2)全局静态变量是显式用 static 修饰的全局变量,作用域是声明此变量所在的文件,其他的文件即使用 extern 声明也不能使用。
2.3 静态局部变量有以下特点:
-
(1)该变量在全局数据区分配内存;
- (2)静态局部变量在程序执行到该对象的声明处时被首次初始化,即以后的函数调用不再进行初始化;
- (3)静态局部变量一般在声明处初始化,如果没有显式初始化,会被程序自动初始化为 0;
- (4)它始终驻留在全局数据区,直到程序运行结束。但其作用域为局部作用域,当定义它的函数或语句块结束时,其作用域随之结束。
一般程序把新产生的动态数据存放在堆区,函数内部的自动变量存放在栈区。自动变量一般会随着函数的退出而释放空间,静态数据(即使是函数内部的静态局部变量)也存放在全局数据区。全局数据区的数据并不会因为函数的退出而释放空间。
3.3 在c++的类中:
-
(1)静态成员函数中不能调用非静态成员。
- (2)非静态成员函数中可以调用静态成员。因为静态成员属于类本身,在类的对象产生之前就已经存在了,所以在非静态成员函数中是可以调用静态成员的。
- (3)静态成员变量使用前必须先初始化(如 int MyClass::m_nNumber = 0;),否则会在 linker 时出错。
一般总结:在类中,static 可以用来修饰静态数据成员和静态成员方法。
静态数据成员
- (1)静态数据成员可以实现多个对象之间的数据共享,它是类的所有对象的共享成员,它在内存中只占一份空间,如果改变它的值,则各对象中这个数据成员的值都被改变。
- (2)静态数据成员是在程序开始运行时被分配空间,到程序结束之后才释放,只要类中指定了静态数据成员,即使不定义对象,也会为静态数据成员分配空间。
- (3)静态数据成员可以被初始化,但是只能在类体外进行初始化,若未对静态数据成员赋初值,则编译器会自动为其初始化为 0。
- (4)静态数据成员既可以通过对象名引用,也可以通过类名引用。
静态成员函数
- (1)静态成员函数和静态数据成员一样,他们都属于类的静态成员,而不是对象成员。
- (2)非静态成员函数有 this 指针,而静态成员函数没有 this 指针。
- (3)静态成员函数主要用来方位静态数据成员而不能访问非静态成员。
再给一个利用类的静态成员变量和函数的例子以加深理解,这个例子建立一个学生类,每个学生类的对象将组成一个双向链表,用一个静态成员变量记录这个双向链表的表头,一个静态成员函数输出这个双向链表。
7.3 mutable
如果想要在const成员函数中修改变量的值,则需要将这些变量定义为mutable的。
mutable是为了突破const的限制而设置的。被mutable修饰的变量,将永远处于可变的状态,即使在一个const函数中。
如果类的成员函数不会改变对象的状态,那么这个成员函数一般会声明成const的。但是,有些时候,我们需要在const的函数里面修改一些跟类状态无关的数据成员,那么这个数据成员就应该被mutable来修饰。
7.4 explicit
explicit可以抑制内置类型隐式转换,所以在类的构造函数中,最好尽可能多用explicit关键字,防止不必要的隐式转换.
explicit关键字只需用于类内的单参数构造函数前面。由于无参数的构造函数和多参数的构造函数总是显示调用,这种情况在构造函数前加explicit无意义。
google的c++规范中提到explicit的优点是可以避免不合时宜的类型变换,缺点无。所以google约定所有单参数的构造函数都必须是显示的,只有极少数情况下拷贝构造函数可以不声明称explicit。例如作为其他类的透明包装器的类。
effective c++中说:被声明为explicit的构造函数通常比其non-explicit兄弟更受欢迎。因为它们禁止编译器执行非预期(往往也不被期望)的类型转换。除非我有一个好理由允许构造函数被用于隐式类型转换,否则我会把它声明为explicit,鼓励大家遵循相同的政策。
例如:CxString string2 = 10;的隐式转换为
CxString temp(10);
CxString string2 = temp;
7.5 volatile
8.虚函数表
参考:
https://www.cnblogs.com/raichen/p/5744300.html
https://blog.youkuaiyun.com/qq_36359022/article/details/81870219
9.new 和 malloc的区别
参考:
https://www.cnblogs.com/engraver-lxw/p/8600816.html
10.结构体内存对齐规则
https://blog.youkuaiyun.com/QuitePig/article/details/7908786?locationNum=1&fps=1
11.overload override overwrite
https://www.cnblogs.com/kuliuheng/p/4107012.html
https://blog.youkuaiyun.com/qq_34793133/article/details/80938099
12.堆与栈的区别
https://blog.youkuaiyun.com/K346K346/article/details/80849966
13.内存溢出和内存泄漏
https://www.cnblogs.com/rgever/p/8899758.html
14.c++内存分区
https://www.cnblogs.com/madonion/articles/2269195.html