本文不涉及一些微妙蛋疼的语法比较, 关注的是宏观方面, 当然后期逐步更新如果, 如果觉得必要, 可能会加上.
议题之一: 初始化的比较
1.CPP基类的任何类构造函数会默认调用父类的不带参数的构造函数, 这点Java也是同样处理的. 子类调用父类的构造函数方式会不同, C++中这样做:
Son::Son(int id):Father(id) {
//Father(10); //注意,这样虽然编译通过,但事实上在构造一个Father类,完了( 出了作用域)之后就立即销毁. 危害非常之大.
cout<<"in Sonconstructor Son(int id) function!"<<endl;
}
2.Son son 这样的方式初始化, 会将一个对象初始化在栈上, 当超出作用域, 自动消除. Son *son这样的方式初始化, 会将一个对象放在堆上, 需要手动Delete, 否则内存泄漏. Son* pSon这样的方式, 没有构造任何对象.
3.上面也意味着, 除基本类型外, Java的对象都是在堆中分配的.
4.构造和析构的基本顺序是《看源代码》:
- $./app.exe
- InMainFunction!
- inFatherItemconstructorFatherItem()function!
- infatherconstructorFather(intid)function!
- inSonItemconstructorSonItem()function!
- inSonconstructorSon(intid)function!
- inSondestructor~Son()function!
- inSonItemdestructor~SonItem()function!
- inFatherdestructor~Father()function!
- inFatherItemdestructor~FatherItem()function!
上面是子类调用父类带参数函数的例子, 基本说明的情况是:
a.父类的成员变量初始化
b.父类的构造函数初始化(看子类调用那个父类的构造函数,默认情况是不带参数的)
c.子类的.h文件中声明的成员变量初始化
d.子类的构造函数调用
析构的顺序正好相反.
这跟Java实质上是一致的, 微弱的区别在于语法表达不同:注意C++引起成员变量的调用, 要么是Son son, 要么是Son* pSon = new Son(); 类似于Son* pSon是没有做初始化的. 不会引起构造函数的调用;而Java中持有的都是引用. 这点需要特别关注, Java中的Son son = new Son()类似于Son* pSon = new Son();(Java中的Son son类似于C++中的Son*pson, 没有做初始化工作). 参见2.
5.关于静态成员变量.
a.Java的静态成员变量在类加载的时候就完成. 类加载是指, 类的首次使用,比如类被构造, 类的其他静态函数或者成员被使用. 因此他会先于所有的成员被初始化. 子类的static成员初始化之前,会先初始化父类的static成员变量, 当静态成员初始化完成之后, 然后参考4的顺序.
b.C++的静态成员变量.
在C++中, 声明静态成员函数是放在.h文件中:
- public:
- staticvoidstatic_function();//静态成员函数
- private:
- FatherItemitemOne;
- FatherItemstaticstatic_fatherWithPara;
将成员变量初始化是放在cpp文件中, 注意跟类定义是类似的:
void Father::static_function() {
// TODO Auto-generated destructor stub
cout<<"in Fatherstatic_function function!"<<endl;
}
FatherItem Father::static_fatherWithPara(10);
当然,结论跟Java是一致的,也即, 类首次加载的时候,完成静态变量的初始化, 加载子类前,首先父类务必先加载. 当类加载成功之后, 在考虑普通变量的初始化,以及构造函数的调用.
6.C++的普通成员初始化.
.h文件中的声明的普通对象被初始化, 比如下面这个:
private:
FatherItem fatherIt;
声明的时候, 先初始化fatherIt, 然后构造函数被调用。跟4的解释一致。但这里就会引申出另外一个问题, 带参数的变量声明,会发生什么, 比如:
private:
FatherItem father(1);
这里要务必注意,这是一个语法错误. 源于声明中存在的二义性问题, 因为我们声明函数也是这么声明的:
private:
ReturnValue FunctionName(Parameter name);
这样编译器看到这个就懵了. 为了清晰起见,我们把这样的声明,还是留给了函数.我们只在头文件中声明变量, 然后在构造函数的外部去定义/初始化这个变量:
在头文件中:
- private:
- FatherItemfatherWithPara;
在.cpp文件的构造函数中:
- Father::Father():fatherWithPara(10){
- cout<<"infatherconstructorFather()function!begin"<<endl;
- cout<<"infatherconstructorFather()function!end"<<endl;
-
- }
这样会带来一个弱点,会发生我们不愿意看到的情况,就是.h中声明的变量,实质上已经被它的默认(即不带参数的)构造函数初始化了, 然后我们在构造函数外部,有对这个变量初始化一次.
——很幸运,这个推断是错误的,结论是: 构造函数外初始化的变量, 在.h中不会被初始化. 也就是说,仅仅初始化一次. 先看我们的测试,马上就可以论证这个结论.
做一个如下的测试,彻底看看对象的初始化过程:
声明两个变量,一个带参数,一个不带参数,这个在头文件中:
- private:
- FatherItemitemOne;
- FatherItemfatherWithPara;
然后在构造函数中初始化fatherWithPara, 但不初始化itemOne, .cpp的代码如下:
- Father::Father():fatherWithPara(10){
- cout<<"infatherconstructorFather()function!begin"<<endl;
- cout<<"infatherconstructorFather()function!end"<<endl;
运行代码可以发现,顺序如下:
$ ./app.exe
In Main Function!
in FatherItem constructor FatherItem() function!//头文件的声明产生的调用
in Constructor FatherItem(int i)function! 10 //构造函数外调用
in father constructor Father() function! Begin //构造函数调用
in father constructor Father() function! End
in Father destructor ~Father() function!
in FatherItem destructor ~FatherItem()function!
in FatherItem destructor ~FatherItem()function!
进一步搞定这个问题的方案是: 即使我们.h文件中的变量声明过了, 我们依然在构造函数的外部, 进行再次初始化:
不难发现, .h文件中声明的变量,如果在构造函数外部被初始化了, 则声明中不会再次初始化.
7.有必要总结一下整个初始化,流程,结合4,5和6. 为描述方便, 假如Son son出现在Main函数中, 即son对象需要被初始化:
A.初始化静态变量, 按照先父(Father类)后子(Son类)的顺序:
1.加载静态变量所在的类
2.加载类同时, 立即初始化该类的所有静态成员变量.
B.按照先父(Father类)后子(Son类)的顺序, 完成以下操作, 注意下面是对一个类进行的操作.
1.初始化类的.h文件中声明的变量(并满足在构造函数外没有被初始化). 调用的是默认构造函数(即不带参数的). 如果在构造函数外出现了成员变量的, .h文件中的变量无需初始化.
2.调用构造函数外所列出的所有成员变量名称涉及的构造方法.
3.调用类的构造函数.
8.有必要约定的规则:
a..h中永远只做声明, 声明了任何变量, 务必在构造函数的外部进行初始化, 即使是不带参数的变量.
b..cpp中永远只做定义.
c.摒弃一切奇技淫巧. 比如今天看到的.h中的声明, 变成定义这样的问题.
附上源码:
源码地址
源码说明:
1. 包含Java和CPP的源代码. 理论上两者都是跨平台的. CPP的是用GCC编译器, 当然用VS肯定是没有问题
2. 主要成员说明: Father类, 持有成员变量FatherItem.
3 Son类, 持有成员变量SonItem
4 Father 和 son是继承关系
5. SonItem和FatherItem没有任何关系.
议题之二: 数据管理
我的个人偏见是,内存管理,实质上是数据管理. 后期展开该话题.
函数参数传递, 全局变量的管理模式, 成员变量的设计思想.
议题之三: 第三方代码的引入或者导出
源码的引入, 比如java会采用import, C++会采用include, using namespace的方式
二进制代码模块的引入, java会引入jar包. C++会引入静态库, 共享库/动态库等
分享到:
相关推荐
JAVA与C++的区别JAVA与C++的区别JAVA与C++的区别JAVA与C++的区别JAVA与C++的区别
本次项目由于服务器之间需要通信加密,java和c++,自己只懂java,因此和同事(c)在网上找了好几个都测试不行,我们修改了其中一个,已通过测试,上传的是最基础的,需要复杂化的可自行修改。为了以后方便他人,贡献...
主要介绍JAVA与C++两种开发语言之间的区别
比较了java与C++的相同点与区别,是面试过程中比较容易问到的问题
The diffenences bwtween Java and C++ (JAVA与C++区别) 内容英文
java与C++的相互调用,使用JNI进行Java与C/C++语言混合编程。
java与c++通过socket通信。其中java作为客户端,c++作为服务器。主要解决了C++中的结构体在java中如何实现和模拟。还有int,float,及字符串的处理。极具代表性。
java与C++严格的比较,适合从java转到c++,或是从c++转到java的开发人员
这个文档是设置Java与c++的通讯。文档中的设置是完全正确的,已经实验证明。觉得不错,所以想大家共同分享。虽然corba已经过期,但它的理念很重要。所以使用它做实验,深化理解。是很必要的。
java与c++的不同 这是Java与C++区别的一个比较完整的答案,大家可以学习一下。
Android操作串口(java与C++混合编程),硬件平台是天嵌的E9开发版,烧的是Android6.0.1系统
JAVA与C++比较.pdf
JNI的小例子 实现java与C++的方法互调 简单易懂 添加注释
本文档总结了java和c++的主要不同的,是个人学习经典的总结。
关于Java与c++的区别,是英文版的,也是我自己整理的,希望对各位有需要应付论文的新生有用
Java采用JNI调用VC++生成的dll(Java与C++交互)
浅析JAVA与C++的区别.pdf