C++复习(三)

1、const在c++中

在默认情况下,全局变量的链接性是外部的,但是const的全局变量的链接性是内部的。

如果希望这个加了coonst的全局变量的链接性是外部的,那么就再给他添加一个extern修饰,但是请记住,鉴于单个const在多个文件之间共享,因此只有文件可对其初始化。

在代码块中声明const时,其作用域为代码块,即仅当程序在执行该代码块中的代码时,该常量才是可用的。这意味着函数和代码块中创建常量时,不必担心名称与其他地方定义的常量发生冲突。

在类中,const 放在函数括号的最后面,保证函数不修改调用对象

2、函数的链接性

c++不允许在一个函数中定义另外一个函数,因此所有函数的储存持续性都自动是静态的,即整个程序执行期间都存在。在默认情况下,函数的链接性是外部的,即可以问价间共享。

可以在函数的原型中使用关键字extern 来指出函数是在另一个文件中定义的,不过这是可选的(要让程序在另一个文件中查找函数,该文件必须作为程序的组成部分被编译,或者是由链接程序搜索的库文件)

可以使用static 将函数的属性设置为内部的,使之只能在一个文件中使用。但是必须在函数声明和定义中都使用该关键字。这样的话,在定义静态函数的文件中,静态函数将覆盖外部文件,因此即使在外部定义了同名的函数,该文件仍将使用静态函数。

3、c++在哪里查找函数

如果该文件中的函数定义为静态的,那么编译器只在该文件中查找函数的定义。否则编译器(包括链接程序)将在所有程序文件中查找。如果找到两个定义,编译器将发出错误消息,因为每个外部函数只能有一个定义。如果在程序文件中没有找到,编译器将在库中搜索。这意味着如果定义了一个和库函数同名的函数,编译器将使用程序员定义的版本,而不是库函数(但是,c++保留了标准库函数的名称,因此程序不应使用它们)。

4、语言的链接性

在c语言中,编译器对于函数的翻译仅仅是在函数的前面加了一个下划线,但是c++中,编译器对于函数的翻译更为复杂。

5、定位的第一次简单认识

int *p1 = new (buffer1) chaff;   //从buffer1中分配空间给结构chaff

int* p2 = new (buffer2) int[20];  //从buffer2中分配空间给一个包含20个元素的int数组

先简单认识一下,后面再详细谈

6、类的大小,一个类的大小就是类中成员变量的之和,当然要考虑内存对齐。注意:空类的大小是1个字节。

7、为什么空类的大小是1个字节?

所谓类的实例化就是在内存中分配一块地址.(空类同样可以被实例化),每个实例在内存中都有一个独一无二的地址,为了达到这个目的,编译器往往会给一个空类隐含的加一个字节,这样空类在实例化后在内存得到了独一无二的地址.因为如果空类不隐含加一个字节的话,则空类无所谓实例化了(因为类的实例化就是在内存中分配一块地址。
继承这个类后这个类大小就优化为0了。这就是所谓的空白基类最优化。

8、为什么要进行内存对齐?

(1)、平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据,某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常

(2)、硬件原因:经过内存对齐之后,CPU的内存访问速度大大提升。

设置内存对齐的对齐数? 

#pragma pack(n),n=1,2,4,8,16

9、 如何知道结构体中某个成员相对于结构体起始位置的偏移量

typedef struct A1 {
	int a;
	char b;
	double c;
}A1;

int main()
{
	int i = (int)(&((A1*)0)->b);
	cout << i << endl;
	system("pause");
	return 0;
}

10、什么是大小端?如何测试某台机器是大端还是小端,有没有遇到过要考虑大小端的场景

  • 大端模式(大端字节序):指的是低字节内容存在高地址,高字节内容存在低地址。

  • 小端模式(小端字节序):指的是低字节内容存在低地址,高字节内容存在高地址。
int main()
{
    int a = 1;
    int i = (int)(*((char*)(&a)));
    cout<<i<<endl; //如果是1,就是小端;如果是0,就是大端。
}

//还可以使用联合体
 
union UN
{
    char c;
    int i; 
}un;

int main()
{
    un.i = 1;
    cout<<c<<endl; //如果是1,就是小端;如果是0,就是大端。
}

11、this指针存在哪里?

其实编译器在生成程序时加入了获取对象首地址的相关代码。并把获取的首地址存放在了寄存器ECX中(VC++编译器是放在ECX中,其它编译器有可能不同)。也就是成员函数的其它参数正常都是存放在栈中。而this指针参数则是存放在寄存器中。类的静态成员函数因为没有this指针这个参数,所以类的静态成员函数也就无法调用类的非静态成员变量。

12、 this指针可以为空吗?

可以为空。

class A1
{
public:
	void test()
	{
		cout << "kakakak" << endl;
	}
	void charge()
	{
		cout << name << endl;
	}
public:
	int name;
};

int main()
{
	A1 a;
	a.test();
	a.charge();
	A1* p = nullptr;
	p->test();
	p->charge();
	return 0;
}

上面代码中当程序运行到 p->charge(); 这句的时候会出错。错误原因就是this指针为空。

为什么呢?当p这个空指针指向test函数时,传给test函数一个空指针,但是没关系,test这个函数并不需要this去调用对象变量,但是当传给charge函数时,相当于让一个空指针去指向一个对象,那么肯定就会报错。

13、不能重载的运算符

.             (成员访问运算符)

.*            (成员指针访问运算符)

::             (域运算符)

sizeof    (长度运算符)

?:            (条件运算符)

14、关于类中const修饰成员函数。

(1). const对象可以调用非const成员函数吗?
(2). 非const对象可以调用const成员函数吗?
(3). const成员函数内可以调用其它的非const成员函数吗?
(4). 非const成员函数内可以调用其它的const成员函数吗?

我们首先清楚一个概念,修饰类中成员函数的const 其本质上是修饰成员函数中的this指针。表明这个成员函数中不允许改变类中成员变量的内容。那么上面的四个问题就特别清楚了。const对象不能改变类中成员变量,而非const成员函数有可能去改变类中成员变量,因此不允许const对象调用非const 成员函数。非const对象允许改变类中成员变量,const 成员函数不允许改变类中成员变量,因此非const 对象调用const成员函数后不会改变类中的成员变量,但是注意:人家非const对象可以调用const成员函数。后面的就更简单了。const成员函数不可以调用其他的非const 成员函数。但是注意:非const 成员函数可以调用其他const成员函数。

15、成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关

16、实现一个类,计算中程序中创建出了多少个类对象。

在类中增加一个static的变量,把类中的构造函数和拷贝构造函数都变成这个变量++。

17、关于静态static 函数和变量。

1. 静态成员为所有类对象所共享,不属于某个具体的实例
2. 静态成员变量必须在类外定义,定义时不添加static关键字
3. 类静态成员即可用类名::静态成员或者对象.静态成员来访问
4. 静态成员函数没有隐藏的this指针,不能访问任何非静态成员

18、malloc/free和new/delete的区别
malloc/free和new/delete的共同点是

都是从堆上申请空间,并且需要用户手动释放。

不同的地方是:
1. malloc和free是函数,new和delete是操作符
2. malloc申请的空间不会初始化,new可以初始化
3. malloc申请空间时,需要手动计算空间大小并传递,new只需在其后跟上空间的类型即可
4. malloc的返回值为void*, 在使用时必须强转,new不需要,因为new后跟的是空间的类型
5. malloc申请空间失败时,返回的是NULL,因此使用时必须判空,new不需要,但是new需要捕获异常
6. 申请自定义类型对象时,malloc/free只会开辟空间,不会调用构造函数与析构函数,而new在申请空间
后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的清理
7. new/delete比malloc和free的效率稍微低点,因为new/delete的底层封装了malloc/free

猜你喜欢

转载自blog.csdn.net/qq_40421919/article/details/86630842