C++进阶

1、

#include <iostream>
using namespace std;

struct SimpleType
{
	double db;
	char sz;
	int n;
};

void main()
{
	SimpleType a;
	int nSize = sizeof(a);
	cout<<nSize<<endl;
}

//输出:nSize = 16

解析:这里nSize的值并非13,而是16。这设计结构体的字节对齐问题。编译器在为结构体变量分配空间时,保证下一个成员的偏移量应为该成员数据类型长度的整数倍。首先为db 成员分配空间,假设起始偏移位置从0开始,db 成员将占用0,1,2,3,4,5,6,7共8字节。接下来为成员变量sz 分配空间,由于char 类型占用1字节,sz 将占据8的位置,因为当前位置8与1是整除的。最后为n 成员分配空间,该成员为int 类型,占用4字节。当前偏移位置为9,并不是4的整数倍,因此需要空出3字节(9、10、11),n 从12的位置开始分配4字节的空间。这样就导致了实际分配的大小与“理论上”的大小不一致。


2、

#include <iostream>
using namespace std;

void OutputString(char data[])
{
	int iSize = sizeof(data);
	cout<<"iSize = "<<iSize<<endl;
}

void main()
{
	int iLen = sizeof("家园");
	cout<<"'家园'的大小为:"<<iLen<<endl;
	OutputString("家园");
}

//输出:
//'家园'的大小为:5
//iSize = 4

解析:作为参数传递的数组其实是以指针的形式传递的,所以在使用sizeof获得数组参数的长度时是4,而不是数字长度。


3、

#include <iostream>
using namespace std;

void main()
{
	int i = 2;
	cout<<(i = 3 * 5, 2 * 4)<<endl;
	cout<<i<<endl;

	int x = 9, y = 7;
	int n = x > y ? (x-y):(x+y);    //三目元表达式
	cout<<n<<endl;
}

//输出:
//8
//15
//2

解析:因为赋值运算符的优先级比逗号运算符的优先级高,所以在上面的代码中,会先计算赋值表达式的值,也就是i=3*5,然后再计算逗号表达式的值,所以 i 的值为15,而逗号表达式的值却是8.

又因为条件运算符的优先级高于赋值运算符,所以会先计算 x>y 的值,然后执行符合条件的表达式(x-y),最后将结果赋值给n。


4、x=x+1、x+=1、++ x 、x ++哪一个的效率最高?

解答:x=x+1最低,因为它的的执行过程为:

(1)读取右x的地址;

(2)x+1;

(3)读取左x的地址;

(4)将右值传给左边的x(编译器并不认为左右x的地址相同)。

其次,x+=1,执行过程如下:

(1)读取左x的地址;

(2)x+1;

(3)将得到的值传给x(因为x的地址已经读出)。

x ++ 相当于下列代码 :

(1)y = x;
(2)x += 1;
(3)return y;

++ x 的效率最高,其执行过程为:

(1)读取右x的地址;

(2)x自增1。


5、

int i=1, j=2, k=3, d=4;
cout<<i+++j<<endl;            //输出:3,先(i++),再(+j),++比+优先级高
cout<<(++k)*(++k)<<endl;        //输出:20,先k自加1等于4,再k自加1等于5,然后4*5=20
(d++)*(d++);
cout<<d<<endl;            //输出:6

!i && j++;
cout<<i<<endl<<j<<endl;  //输出:2   3,因为!i运算结束后,整个表达式已肯定为假,所以不必再去计算后面的式子


6、if("A" == a) 比 if(a == "A") 更好,因为如果把”==“误写成”=“,编译器就能检查到错误,因为编译器不允许对常量进行赋值。


7、自动转换遵循以下规则:

1)若参与运算量的类型不同,则先转换成同一类型,然后进行运算。

2)转换按数据长度增加的方向进行,以保证精度不降低。如int型和long型运算时,先把int量转成long型后再进行运算。

     a.若两种类型的字节数不同,转换成字节数高的类型

     b.若两种类型的字节数相同,且一种有符号,一种无符号,则转换成无符号类型

3)所有的浮点运算都是以双精度进行的,即使仅含float单精度量运算的表达式,也要先转换成double型,再作运算。

4)char型和short型参与运算时,必须先转换成int型。

5)在赋值运算中,赋值号两边量的数据类型不同时,赋值号右边量的类型将转换为左边量的类型。如果右边量的数据类型长度左边长时,将丢失一部分数据,这样会降低精度,丢失的部分按四舍五入向前舍入。

 扩展:

       (1). 在表达式中,char 和 short 类型的值,无论有符号还是无符号,都会自动转换成 int 或者 unsigned int(如果 short 的大小和 int 一样,unsigned short 的表示范围就大于 int,在这种情况下,unsigned short 被转换成 unsigned int)。因为它们被转换成表示范围更大的类型,故而把这种转换称为“升级(promotion)”。 

      (2). 按照从高到低的顺序给各种数据类型分等级,依次为:long double, double, float, unsigned long long, long long, unsigned long, long, unsigned int 和 int。这里有一个小小的例外,如果 long 和 int 大小相同,则 unsigned int 的等级应位于 long 之上。char 和 short 并没有出现于这个等级列表,是因为它们应该已经被升级成了 int 或者 unsigned int。 

      (3). 在任何涉及两种数据类型的操作中,它们之间等级较低的类型会被转换成等级较高的类型。 

      (4). 在赋值语句中,= 右边的值在赋予 = 左边的变量之前,首先要将右边的值的数据类型转换成左边变量的类型。也就是说,左边变量是什么数据类型,右边的值就要转换成什么数据类型的值。这个过程可能导致右边的值的类型升级,也可能导致其类型降级(demotion)。所谓“降级”,是指等级较高的类型被转换成等级较低的类型。 

      5. 作为参数传递给函数时,char 和 short 会被转换成 int,float 会被转换成 double。使用函数原型可以避免这种自动升级。


8、交换两个数:

//方法一:
temp = a;
a = b;
b = temp;

//方式二:
a = a + b;
b = a - b;
a = a - b;

//方式三:(推荐)
a = a ^ b;
b = a ^ b;
a = a ^ b;


9、在C++中调用被C编译器编译后的函数,为什么要加 extern "c"?

答:C++语言支持函数重载,C语言不支持函数重载,函数被C++编译后在库中的名字与C语言的不同。假设某个函数的名称为:void fun(int x, int y),该函数被C编译器编译后在库中的名字为_fun,而C++编译器则会产生像_fun_int_int之类的名字。C++提供了C连接交换指定符号extern ”C“解决名字匹配问题。


10、

#include <iostream>
#include <cstring>
using namespace std;

class A
{
    
};
class B
{
    char a, b;
    B();
    ~B();
};
struct C
{
    
};
struct D
{
    int a;
    char b;
};
struct E
{
    long a1;
    short a2;
};
struct F
{
    int a;
    static int b;
};

int main()
{
    A *p1= new A();
    A p2;
    A *p3;
    char *ss1 = "0123456789";
    char ss2[] = "0123456789";
    char ss3[100] = "0123456789";
    int ss4[100];
    char q1[] = "ABCDEF";
    char q2[] = "a\n";
    char *q3 = "a\n";
    string x[] = {"aaa", "bbb", "ccc"};
    void *i;
    char *str1 = (char *)malloc(100);
    void *str2 = (void *)malloc(100);
    
    cout<<"sizeof(p1): "<<sizeof(p1)<<endl;
    cout<<"sizeof(p2): "<<sizeof(p2)<<endl;
    cout<<"sizeof(p3): "<<sizeof(p3)<<endl;
    cout<<"sizeof(ss1): "<<sizeof(ss1)<<endl;
    cout<<"sizeof(*ss1): "<<sizeof(*ss1)<<endl;
    cout<<"sizeof(ss2): "<<sizeof(ss2)<<endl;
    cout<<"sizeof(ss3): "<<sizeof(ss3)<<endl;
    cout<<"sizeof(ss4): "<<sizeof(ss4)<<endl;
    cout<<"sizeof(q1): "<<sizeof(q1)<<endl;
    cout<<"sizeof(q2): "<<sizeof(q2)<<endl;
    cout<<"sizeof(q3): "<<sizeof(q3)<<endl;
    cout<<"sizeof(x): "<<sizeof(x)<<endl;
    cout<<"sizeof(A): "<<sizeof(A)<<endl;
    cout<<"sizeof(B): "<<sizeof(B)<<endl;
    cout<<"sizeof(C): "<<sizeof(C)<<endl;
    cout<<"sizeof(D): "<<sizeof(D)<<endl;
    cout<<"sizeof(E): "<<sizeof(E)<<endl;
    cout<<"sizeof(F): "<<sizeof(F)<<endl;
    cout<<"sizeof(str1): "<<sizeof(str1)<<endl;
    cout<<"sizeof(str2): "<<sizeof(str2)<<endl;
    cout<<"sizeof(""): "<<sizeof("")<<endl;
    cout<<"sizeof(\"明\"): "<<sizeof("明")<<endl;
    cout<<"sizeof(i): "<<sizeof(i)<<endl;
}

/*输出:
sizeof(p1): 4
sizeof(p2): 1
sizeof(p3): 4
sizeof(ss1): 4
sizeof(*ss1): 1
sizeof(ss2): 11
sizeof(ss3): 100
sizeof(ss4): 400
sizeof(q1): 7
sizeof(q2): 3
sizeof(q3): 4
sizeof(x): 48
sizeof(A): 1
sizeof(B): 2
sizeof(C): 1
sizeof(D): 8
sizeof(E): 8
sizeof(F): 4
sizeof(str1): 4
sizeof(str2): 4
sizeof(): 1
sizeof("明"): 3
sizeof(i): 4
*/

解析:

        

        空类所占空间为1,单一继承的空类也为1,多继承的空类还是1,但虚继承涉及到虚表(虚指针),其所占空间为4.


11、类中的this指针有以下特点:

(1)this只能在成员函数中使用,在全局函数、静态函数中都不能使用this;

(2)this在成员函数的开始前构造,在成员函数结束后清除;


12、C++中有了malloc/free,为什么还要new/delete?

答:malloc和free是C++/C语言的标准库函数,new和delete是C++的运算符。对于非内部数据类型的对象而言,光用malloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于new/delete。因此C++需要一个能够完成动态内存分配和初始化工作的运算符new,以及一个能完成清理与释放内存工作的delete。


13、

#include <iostream>
using namespace std;

class A
{
public:
	virtual f()
	{
		cout<<"A"<<endl;
	}
};

class B : public A
{
public:
	virtual f()
	{
		cout<<"B"<<endl;
	}
};

void main()
{
	A* pa = new A();
	pa->f();
	B* pb = (B *)pa;
	pb->f();
	delete pa, pb;
	pa = new B();
	pa->f();
	pb = (B *)pa;
	pb->f();
}

/*输出:
A
A
B
B
*/

214958_OXlt_580523.png


14、

#include<iostream>
using namespace std;

class A
{
	char a[3];
	virtual void aa() {};
};
 
 class B : virtual public A
 {
 	char b[3];
 	virtual void bb() {};
 };
 
 class C : public A
 {
 	char c[3];
 	virtual void cc() {};
 };
 
int main()
{
 	A a;
 	B b;
 	C c;
 	cout<<sizeof(a)<<endl;
 	cout<<sizeof(b)<<endl;
 	cout<<sizeof(c)<<endl; 
 	return 0;
 }


转载于:https://my.oschina.net/Jacedy/blog/343692

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值