C++的一些基础知识点
前缀加与后缀加的区别:
-
前缀加:++i 的操作结果是先进行加的运算,之后再将加完之后的结果返回;
-
后缀加:i++ 的操作结果则是先返回未加的i的值,之后再进行加一的操作;
printf()函数的返回值:📝
该函数返回打印字符串中字符的个数,包含结束符'/0';
inline函数的默认存储类型:
inline函数在文件作用域中默认是static存储类型的;
默认值的确定:
默认值不允许是局部变量,因为默认参数的函数调用是在编译时确定的,应该使用的是静态或者全局变量;
void *指针(仅仅是一个地址):
不能进行指针运算,也不能进行间接引用;但是可指向任意类型的数据,即可以用任意类型的指针或者对void指针进行赋值;比如:
int * a;
void * p;
p = a;
NULL与void * 的区别:
NULL是一个指针指向的数值,任何类型都可赋值该值,而void *是一种类型,是一种无任何类型的指针;
左值与右值的区别:
当一个对象被用作右值的时候,用的是对象的值(内容);当对象被用作左值的时候,用的是对象的身份(在内存中的位置)。左值与右值的根本区别在于是否允许取地址&运算符获得对应的内存地址。
在main函数中的参数意义:
int main(int argc,char * argc[])
{
return 0;
}
其中argc表示参数的个数,argv表示参数的数组;
通过函数返回多个值:
在函数中,只能返回一个值;需要函数返回多个值时,可以使用引用或者指针进行传递需要返回的值,进而达到函数能够返回多个值的目的;
sizeof()使用的结论:
-
sizeof是运算符,不是函数;
-
sizeof不能求得void类型的长度;(因为无法声明void类型的变量,而声明变量的一个重要作用就是告诉编译器该变量需要多少存储空间)
-
sizeof能求得void类型的指针的长度;
-
sizeof能求得静态分配内存的数组的长度;
-
sizeof不能求得动态分配的内存的大小;
-
sizeof不能对不完整的数组求长度;
-
当表达式作为sizeof的操作数时,它返回表达式的计算结果的类型大小,但是它不对表达式进行求值;
-
sizeof可以对函数调用求大小,并且求得的大小等于返回类型的大小,但是不执行函数体;
-
sizeof求得得结构体(及其对象)得大小并不等于各个数据成员对象的大小之和;(对齐规则下的结果)
-
sizeof不能用于求结构体的位域成员的大小,但是可以求得包含位于成员的结构体的大小;
类的继承以及不同的访问标识符限定的访问范围🔪
类的继承后方法属性变化:
-
private 属性不能够被继承。
-
使用private继承,父类的protected和public属性在子类中变为private;
-
使用protected继承,父类的protected和public属性在子类中变为protected;
-
使用public继承,父类中的protected和public属性不发生改变;
private, public, protected 访问标号的访问范围:
private:只能由1.该类中的函数、2.其友元函数访问。
不能被任何其他访问,该类的对象也不能访问。
protected:可以被1.该类中的函数、2.子类的函数、以及3.其友元函数访问。
但不能被该类的对象访问。
public:可以被1.该类中的函数、2.子类的函数、3.其友元函数访问,也可以由4.该类的对象访问。
注:友元函数包括3种:设为友元的普通的非成员函数;设为友元的其他类的成员函数;设为友元类中的所有成员函数。
虚函数的限制🎶
使用基类对象指针或者引用调用虚函数时,该调用将被动态绑定;根据引用或者指针所绑定的对象类型不同,该调用执行对应对象的函数版本;可能是执行基类的版本,也可能是执行派生类的版本;
- 只有类的成员函数才能说明为虚函数;虚函数仅适用于有继承关系的类对象,则普通函数不能是虚函数;
- 静态成员函数不能是虚函数;因为静态成员函数不受限于某个对象;
- 内联函数不能是虚函数;内联函数是不能在运行中动态确定其位置,即使声明为并定义,编译时,也会被认定是非内联的函数;
- 构造函数不能是虚函数;因构造函数是针对对象进行实例化的,在构造过程中,对象还是未定型的空间,因此不能实现运行确定对象的作用;
- 析构函数可以是虚函数,并且通常声明为虚函数;
多重继承的构造顺序:
虚拟继承 > 非虚拟继承 > 成员对象 > 自己的构造
-
任何虚拟基类的构造函数按照它们被继承的顺序构造;
-
任何非虚拟基类的构造函数按照它们被继承的顺序构造;
-
任何成员对象的构造函数按照它们声明的顺序构造;
-
类自己的构造函数;
运算符重载:
什么是运算符重载?
- 运算符重载是通过创建运算符函数实现的,运算符函数定义了重载的运算符将要进行的操作。运算符函数的定义与其他函数的定义类似,惟一的区别是运算符函数的函数名是由关键字operator和其后要重载的运算符符号构成的。运算符函数定义的一般格式如下:
<返回类型说明符> operator <运算符符号>(<参数表>)
{
<函数体>
}
为什么要重载运算符?
- C++中预定义的运算符的操作对象只能是基本数据类型。但实际上,对于许多用户自定义类型(例如类),也需要类似的运算操作。这时就必须在C++中重新定义这些运算符,赋予已有运算符新的功能,使它能够用于特定类型执行特定的操作。运算符重载的实质是函数重载,它提供了C++的可扩展性,也是C++最吸引人的特性之一。
比如,我们定义两个string类对象a,b后我们之所以可以使用+运算,是因为string类重载了+运算符。
可否重载的运算符:
- 可以被重载的运算符 :
算术运算符:+ , - , * , / , % , ++ , –
位操作运算符:& , | , ~ , ^ , << , >>
逻辑运算符:! , && , ||
比较运算符:< , > , >= , <= , == , !=
赋值运算符:= , += , -= , = , /= , %= , &= , |= , ^= , <<= , >>=
其他运算符:[] , () , -> , ,(逗号运算符) , new , delete , new[] , delete[] , -> - 下列运算符不允许重载:(与点有关的都不能重载,外加->)
. , . , :: , ?:,->*
如何重载运算符?
运算符函数重载一般有两种形式:重载为类的成员函数和重载为类的非成员函数。非成员函数通常是友元。
如果一个运算符函数是成员函数,则它的第一个(左侧)运算对象绑定到隐式的this指针上,因此,成员运算符函数的(显式)参数数量比运算符的运算对象总少一个(后置单目运算符除外,后面会介绍到)。
class A
{
private:
int a;
public:
A operator+(A&);
A()=default;
A(int x):a(x){}
};
A A::operator+(A& d)
{
return A(a+d.a);
}
int main()
{
A b,c,d;
d=b+c; //等价于d=b.operator+(c);
return 0;
}1234567891011121314151617181920
当运算符函数是非成员函数时,函数的参数与该运算符作用的运算对象数量一样多。
class A
{
private:
int a;
public:
friend A operator+(A&,A&);
A()=default;
A(int x):a(x){}
};
A operator+(A& c,A& d)
{
return A(c.a+d.a);
}
int main()
{
A b,c,d;
d=b+c; //等价于d=operator+(b,c);
return 0;
}
两种重载形式的比较:
在多数情况下,将运算符重载为类的成员函数和类的友元函数都是可以的。但成员函数运算符与友元函数运算符也具有各自的一些特点:
- 赋值(=),下标([]),调用( ( ) ),和成员访问箭头(->)运算符必须是成员。
- 复合赋值运算符一般来说应该是成员,但并非必须,这一点与赋值运算符略有不同。
- 改变对象状态的运算符或者与给定类型密切相关的运算符,如递增,递减,和解引用运算符,通常应该是成员。
- 具有对称性的运算符可能转换任意一端的运算对象,例如算术,相等性,关系和位运算符等,因此它们通常应该是普通的非成员函数。
注意事项:
-
对于一个运算符函数来说,它或者是类的成员,或者至少含有一个类类型的参数
int operator+(int ,int); //error,不能为int重定义内置的运算符 -
重载运算符限制在C++语言中已有的运算符范围内的允许重载的运算符之中,不能创建新的运算符。
-
重载之后的运算符不能改变运算符的优先级和结合性,也不能改变运算符操作数的个数及语法结构。
-
&&和||运算符的重载版本无法保留内置运算符的短路求值属性,两个运算对象总是会被求值。因此不建议重载它们。
-
通常情况下,不应该重载逗号,取地址,逻辑与和逻辑或运算符。
-
使用与内置类型一致的含义。重载运算符的返回类型通常情况下应该与其内置版本的返回类型兼容:逻辑运算符和关系运算符应该返回bool,算术运算符应该返回一个类类型的值,赋值运算符和复合赋值运算符应该返回左侧运算对象的一个引用。
-
C++约定,在增量运算符定义中,放上一个整数形参,就是后增量运算符。如:
-
class Increase{ int value; public: Increase(int x):value(x){} /*因前增量是在原有的基础上进行加操作,因此需要返回原有对象 就使用对象引用进行返回*/ Increase& operator ++(); //前增量 ++a /*后增量则是先使用临时对象保存当前对象,之后进行加操作 并且返回保存原有对象的临时对象,因此不能够使用引用*/ Increase operator ++(int) //后增量 a++ };

浙公网安备 33010602011771号