- const用法以及问题
首先:
const int *p
int const *p
这两个都是一个意思,都是常量指针,只能修改指向不能修改里面值的const主要的是(*p)
int * const p
这个是指针常量不能修改指向,只能修改里面的值const主要的是(p)
通过两个的比较可以简单的通过星星的位置来记忆,星星在const右边的常量指针,星星在const左边的时候就是指针常量
const int* p const
这样不管是值还是变量都是不能修改的
简单来说就是看指针在前还是在后.
const 还可以拿来修饰输入的值对输入的引用类型和指针类型进行保护以免失误修改了。
void p(const int* a)
void p(const int& a)
同时,const还可以拿来对函数返回值使用
const int x() const
这样无论是对返回值的地址或者其中变量都不能进行修改了当然还有一切方法可以破解,不过一般写代码情况下基本能满足
- 函数指针\指针函数问题
简单的说。。返回值是指针的就是指针函数了
比如:
void* p();
如上就是一个返回值为空指针的函数,这个就是指针函数
指针函数的话如下:
void (指针名字*)(参数)
这个就是一个函数指针了,他可以指向参数相同,返回值相同的一个函数,做一些跨类使用函数来说很方便。
比如说:
if (int < int)
当你的函数里面不想用这种比较方式想要灵活点的每次调用都想比较不同的数据那么就可以用这个指针函数了
if (p)比如像这样来进行比较函数等等
void (p*)(int,int)
{
return int >= int
或者
return int < int ? int : int
}
可以使用typedef来替换名字的方式调用
typedef void (*Fined)();
Fined f = XXX;
- 申请内存问题malloc和new的区别
区别很简单啊C++说到底还是C出生所以new的时候实际上还是调用的malloc来进行分配,但是唯一不同的是,在分配的同时还会调用类的构造释放的时候会调用析构,在说细点就是malloc分配出来的内存是空类型的需要进行强转。
- 运算符\位运算符
C++中运算符使用是很频繁的相对重要一些如下
1. % 取模运算符(取余数使用除法结果不为整数时结果为多出来的)
2. & 按位与(作为比较底层的一个判断如: 0001 & 0001结果是相同为0001,同位都为1才为1 ,否则为0)
还可以说:& (与):两个都是真(1)时,结果才是真->同&&逻辑与相同
3. | 按位或(同与相同都是底层的判断如:1001 | 0101结果为1101只要相同位有一个为1都为1,否则为0)
还可以说 : | (或):有一个是真(1)时,就是真->同|| 逻辑或相同
4. ^ 按位取异或(如:0000 ^ 1111结果为 1111同位不想同为1,否则为0)
还可以说 : ^ (异或):相同为假(0),不同为真
5. ~ 按位非(按位取反+1如:~5 \ (0000 0101)结果为1111 1010 )
在有负数的时候取绝对值+1如 :
-12最高位有 符号所以为:1111 0011
1111 0011 取反 0000 1101 = 13
6. ! 逻辑非 (判断中使用判定是否为此结果相反)
if (!true)
跳过
else
执行
7. && 逻辑与(相同为真不同为假)
if (true && true)
执行
else
跳过
8. || 逻辑或(一个为真就为真,同时为假才为假)
if (true || false)
执行
else
跳过
- 数据类型的取值范围
- char a1=-128;//-128~+127
- short b1=-32768;// -32768~+32767
- int c1=-2147483648;//-2147483648~+2147483647
- long d1=-2147483648;//-2147483648~+2147483647
- long long x1=-9223372036854775808;//-9223372036854775808~9223372036854775807
- //以下取-1转化后为最大值
- unsigned char a2=-1;//0~255
- unsigned short b2=-1;// 0~65535
- unsigned int c2=-1;//0~4294967295
- unsigned long d2=-1;//0~4294967295
- unsigned long long x2=-1;//0~18446744073709551615
- float e=100/3.0;//10e±38,6位有效数字-7
- double f=100.0/3;//10e±308,12位有效数字-16
- long double g=100.0/3;//10±4932,15位有效数字-16
- &取地址运算符与引用
一般情况下这样定义 int* p = &a(吧a的地址赋值给P)
还有一种用法就是引用,引用的话一般用于函数中形参的引用
基本使用:
int& p = a;
这个定义引用必须要初始化,这个不是很方便,引用也就是给a变量取一个别名。
还有引用了过后不能改变引用的对象了直接引用相对于指针的灵活性就差了点如:
int a = 1;
int b = 2;
int& c = a;
a = b//在这里相当于吧b的值赋值给a (a = 2)那么结果就会都等于2了
引用还不能引用赋值为null,必须是有值的合法的单位
int& a = null//这个是错误的
int* a = null;
int& b = *a;//这样是可以输出的,但是会造成不可预知的错误情况。。
函数中的使用:
void xx(int& p);
在参数中使用的话是不会生成一个副本的,因为他就是变量的一个别名,可以直接访问;
在这里就可以说一下与指针的不同,就在于指针要创建一个副本出来然后副本还要执行拷贝构造消耗上过于大了。。当然对于当前电脑来说这点可以理论可以忽略了。。。
- 类的private/protected/public属性
1、类的成员如果没有指定访问域,默认是private的。
2、标识符protected 与 private类似,它们的唯一区别在继承时才表现出来。当定义一个子类的时候,基类的protected 成员可以被子类的其它成员所使用,然而private 成员就不可以。
3、public/protected/private继承的区别:
(1)public继承:父类的public依然是public,protected依然是protected,private不可访问;
(2)protected继承:父类的public称为protected,protected称为private;
(3)private继承:父类的所有成员全部变成private。
- 关于空类
空类占用空间为1不会为0
在一个空的类中。。一样会默认给出基本的构造。析构。还有拷贝构造等
- 在继承中构造和析构的执行顺序
如:
class A : B{...}构造执行顺序是B ' A,析构的话是反过来的.
- 纯虚函数,虚函数
被virtual修饰的就是虚函数在一个父类中必须有一个虚函数这样编译器才会生成一个虚函数表来保存子类的实现函数
virtual void p();虚函数可以不用实现
virtual void p() = 0;纯虚函数必须实现
- 运算符重载
实现为
type operator +();
- 友元
友元类:
class A{friend class XXX}
友元函数:
在函数声明前加上friend,友元函数不是类中成员函数,实现时可以不加类名
- 模版
实现语法:
tempelate<typename T>
class A{T data}
- 指针和数组的区别
数组要么在全局数据区被创建,要么在栈上被创建;指针可以随时指向任意类型的内存块;
修改内容上的差别:
char a[] = “hello”;
a[0] = ‘X’;
char *p = “world”; // 注意p 指向常量字符串
p[0] = ‘X’; // 编译器不能发现该错误,运行时错误
(*p) = 'X';
用运算符sizeof 可以计算出数组的容量(字节数)。sizeof(p),p 为指针得到的是一个指针变量的字节数,而不是p 所指的内存容量。C++/C 语言没有办法知道指针所指的内存容量,除非在申请内存时记住它。注意当数组作为函数的参数进行传递时,该数组自动退化为同类型的指针。
- 面对对象的基本概念
封装,继承,多态就是面对对象的基本特征了。
封装: 通常看到吧抽象的事物封装成类这个说发,但是这个说法太抽象了,实际上也可以说,把多个模块组合起来,形成一个更加完善的实体。
继承: 按早C++来说就是子类继承父类,不过子类能使用的就只有公开继承的那一部分, 在继承关系中,就算被保护的,私有的,都是会被继承下来不过不能使用罢了,在写类继承时候还是要多注意一下,继承的体量了。
多态: 简单的说就是子类实现了父类的虚函数, 父类的指针指向子类时调用虚函数。
- 类的构造析构是否能为虚
构造是不能成为虚函数的,因为虚函数表是在构造中初始化,如果还没执行都不能加入到虚函数表中,就算不会报错调用也是没任何效果的.再者虚函数采用一种虚调用的方法。需调用是一种可以在只有部分信息的情况下工作的机制。如果创建一个对象,则需要知道对象的准确类型,因此构造函数不能为虚函数.
析构是可以成为虚函数的,析构在继承体系中如果有子类最好还是写成虚函数,这样才能保证释放时一定会执行所有的析构
- 有哪几种情况只能用构造函数初始化列表而不能用赋值初始化?
const成员,引用成员
- 堆,栈,静态不同
栈: 由编译器自动分配和释放,如: 局部变量和函数的参数
堆: 一般由程序员动态分配,使用关键字malloc,free,new,delete
静态: 全局和静态变量都是放到这里面的
还有一些如常量内存区: 字符串等就放在这里面,程序结束就会释放
代码区: 二进制代码区(这些估计了解一下就行了。。有兴趣的可以继续研究下去)
- static全局变量与普通的全局变量有什么区别?static局部变量和普通局部变量有什么区别?static函数与普通函数有什么区别?
static全局变量与普通全局变量区别:static全局变量只初使化一次,防止在其他文件单元中被引用;
static局部变量和普通局部变量区别:static局部变量只被初始化一次,下一次依据上一次结果值;
static函数与普通函数区别:static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝。
- 一个父类写了一个 virtual 函数,如果子类覆盖它的函数不加 virtual ,也能实现多态?
- 在子类的空间里,有没有父类的这个函数,或者父类的私有变量? (华为笔试题)
只要基类在定义成员函数时已经声明了 virtue关键字,在派生类实现的时候覆盖该函数时,virtue关键字可加可不加,不影响多态的实现。子类的空间里有父类的所有变量(static除外)。
- 父类和子类的析构调用顺序
(首先是析构必须要是虚析构)析构的调用顺序是先调用子类的析构然后再调用父类的析构,也就是说在调用父类的析构的时候子类析构已经全部调用完毕了,在构造的时候先调用的是父类构造,然后再调用子类构造,析构的时候是相反的
- 函数参数问题
1.参数分为形式参数和实际参数
形式参数:在定义函数时,函数名后面括号中的变量名称叫做“形式参数”,或者称为“形参”
实际参数:在调用函数时,函数名后面括号中的变量名称叫做“实际参数”,或者称为“实参”
首先要知道给一个函数传递实际参数过后,这个实际参数还是否是传递进来的这个值。
通常情况下在传递参数进入函数过后,这个值只是一个复制体和原来的变量是没任何关系的只是说这两个是相等的。
所以很多函数都是在内部计算过后返回一个指针或者一个值出去,不然退出作用域会被释放变成无意义的执行。