NDK学习(四)C++开篇

之前学习过C++,但是几乎都忘的差不多了,连语法好多都忘了,因此就C++几个重要的点复习一下,顺便深入C++的内存模型来探讨C++和C有什么区别和共同点,C++的多态实现和Java的多态有什么不同,另外就C++的一些专有特性写一些文章,比如:模板、运算符重载、STL模版库、复制构造函数等。

其实从编译得到的可执行文件来讲,C和C++并没有什么不一样,都是二进制代码,访问变量,就是到相应的地址获取变量,调用函数时就是确定函数的地址,改保存的参数全部进栈,参数相应也入栈,然后将程序执行的pc指针指向函数,运行即可,如果需要动态链接,那么就在需要的时候,到相应的路径找到动态链接库,加载动态链接库到内存空间中,然后跳转到相应的函数地址。上面的过程C和C++完全一样,因此可以说C和C++在这个层面上是一模一样的,没有什么分别。这个还和Java不同,Java无论是编译的产物和运行中对方法调用的处理都完全不一样。C和C++的主要区别就在于C/C++编译器和两者的语法层面有很大的不同,首先语法层面C++是面向对象的,因此就有很多的特性,封装、继承、多态、模板、对象这些都是新增的特性,另外C++编译器为我们做的事很多,以至于在很多时候都会产生连我们都很惊讶的结果,这个我下面会说几个,正因为C++在编译的期间为我们做了大量的事,导致我们不一定很清楚C++编译器到底在我们的代码中做了什么手脚,这也是C++这门语言难以学习的地方。

大致列举几个C++编译器为我们做的事情:
1、对函数的重命名

class C
{
public:
	void fun(int a,double b);
};
void C::fun(int a, double b)
{
}

编译出来得到的可执行文件,使用readelf查看符号表,得到最终fun函数的形式:为_ZN1C3funEid,这在C语言中是没有的,C++编译器这样做的原因是C++需要支持命名空间和类的继承,很难想象如果不对fun重命名,不同类里面同名函数将如何处理。有人也许会说Java有没有这样处理呢?这个我不是很清楚,因为在Java中还有jvm,这个jvm为Java做了非常多的事情,而C++只要经过编译之后,就只剩下二进制文件了,里面类的信息几乎已经不存在了,直接由系统来运行其代码,里面方法的调用也基本确定了地址,除了virtual方法,virtual方法其实也是通过一些手段在运行时确定下来,动态性并不是很强,因此C++还不能说是一门高级语言,应该是一门中级语言,它既有C语言强大的运算能力,因此多用于密集计算,又没有像Java、Python、Js那样,在运行时能确定类对象和类里面所有信息,而且像Python、Js还能在运行时给对象添加方法。

2、空类大小和迷人的sizeof操作符

class A
{
public:
    int a;
    char b;
};

class B
{
};

int main()
{
    cout << sizeof(A) << endl;
    cout << sizeof(B) << endl;
    return 0;
}

结果为:8 和 1
因为cpu在读取数据的时候,往往只能读取某些地址的值,比如只能读取偶数位置的数据,当需要读取奇数位置的数据就读取临近两个偶数位置的数据,然后拼凑出改奇数位置的数据,这样的话,数据读取的事件要稍微长一点,因此本着以空间换时间的观念,编译器在编译的时候,会有数据对齐的操作,向A里面填充一些无用的空间,因此A的sizeof要大一些。
B是一个空的class,为了不使两个不同的对象拥有相同的地址,编译器会为空的class默认添加一个字节的空间。

3、谜一样的指针转换

class A
{
public:
    int a1;
};

class B
{
    int b;
};

class C : public A, public B
{
};

int main()
{
    C *pc = new C();
    A *pa = pc;
    B *pb = pc;
    cout << pa << endl;
    cout << pc << endl;
    cout << pb << endl;
    if (pb == pc)
    {
        cout << "hello" << endl;
    }
    return 0;
}

输出结果:

0x55863007ceb0
0x55863007ceb0
0x55863007ceb4
hello

我似乎已经听到了读者卧槽的声音,妈的,这几个指针明明指向的是同一对象,为什么输出来的值不一样,而且值都已经不一样了

if (pb == pc)
    {
        cout << "hello" << endl;
    }

这个语句竟然为true,这到底是怎么回事。
具体原因我不知道,但是我可以从C++的内存模型大致猜一下如果指针的值是相同的会导致什么后果,先看一下C类的内存结构:

在这里插入图片描述
a1和b分别是从A和B继承而来的,pa和pc这两个指针指向同一地址这个很好理解,因为C的继承关系是把A放在前面的,因此A的成员也是在对象的头部位置,如果pb等于pc的话,那么通过pb去获取b这个值就会不对,因为C++获取对象实际上是通过该变量相对于对象头部的偏移来获取的,b相对于B这个类的偏移是0,类似的如果有其他的值的话,也会获取到不正确的值,这也是为什么pb为什么不等于pc的原因,所以说

B *pb = pc;

这句代码编译器为我们做了一些手脚,这一块一定要注意,要深究为什么就需要看汇编代码了,但是我汇编代码能力有限,只能靠读者去探索了,如果有知道为什么的读者,可以加在评论里面,让后面的人也能明白。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值