Java 转 C++ 那些事
Posted 法海你懂不
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java 转 C++ 那些事相关的知识,希望对你有一定的参考价值。
前提纪要
虽说编程语言只是承载思想的一种媒介,但是每种编程语言有自己的设计哲学,所以在实现自己思想的时候,也需要遵循该门语言的理念才行。截止 2022 年 07 月 12 日本人最大的体验是,Java 这门语言存在大量的过度封装(所以能封装成类就封装成类),C++ 这门语言有不少奇技淫巧(所以各种奇怪的茴香豆五种写法),所以编程体验差异很大。本文主要描述了 Java 程序员转 C++ 程序员写代码时那些不习惯的开发方式。
结果是对的,但它可能是不对的。
基础设施非常不完善
Java 中的包管理工具有 Maven, Gradle 等,但是 C++ 就一个 CMake(还有 Blade),对于引入的包的版本管理就是个空白,想要更新依赖的包,那就必须重新下载源码,重新编译。
变量生命周期短的可以
C++ 变量的生命周期非常短,出了 往往就意味着生命周期结束了(除非是使用 new 在堆上定义一个对象)。最危险的莫过于返回了局部对象的引用或者指针。
int64_t* test1()
int64_t arr[] = 1, 3, 5;
return arr;
int64_t* p = test1();
这样的写法,在 Java 中是没有问题的,但是 C++ 中就会出现结果不符合预期的情况(不会报错),原因就是 arr 是定义在函数内的局部变量,一旦 return 之后就释放掉了。
但是呢,返回一个值是对的(这个值即是个对象也行,未使用 new)
int test1()
int64_t p = 1;
return p;
int num = test1();
这倒不是因为变量 p 的生命周期延长了,而是将临时变量 p 的结果通过拷贝的形式赋值给了 num。所以这里就引入了一个非常细节的问题,如果返回的是个对象,那么这个对象对应的类应该实现了拷贝构造函数来支持深拷贝,不然结果最后在函数外使用该临时变量的结果可能会不符合预期。对于 C++ 的基本类型,值拷贝一般也不会出什么问题。这里需要注意 Return Value Optimization(RVO),它可能让中间的表现形式看起来不是自己想的那样(比如不会调用拷贝构造函数之类的)。
函数返回值类型越简单越好
C++ 的返回值一般不会使用对象返回(除非该对象非常简单,函数逻辑同样非常简单)。
uint64_t Encrypt(Request& request, Response& response)
...
return 0;
C++ 一般会写成上述风格,但是 Java 一般会写成下述风格。
public Response Encrypt(Request request)
Response resp = new Response();
...
return resp;
函数传递的参数既是参数也是结果
C++ 的参数一般使用指针或者引用传递参数,很少使用值传递的方式来传参,除非确定值传参的性能会更高。不过指针和引用都能避免传递参数的拷贝,有时抉择使用哪个还挺难办的,目前个人更倾向入参使用引用,出参使用指针。当然 Java 中的对象传值都是引用的方式,所以这种形式也天然支持,不过就个人历史经验而言,很少见到这种形式的写法。
uint64_t Encrypt(Request& request, Response* response)
...
return 0;
定义对象更加侧重充血模型
Java 项目中,尤其 Web 项目中,一般会以定义贫血模型为主(部分项目也会定义充血模型,尤其社区项目),C++ 中几乎很难看到贫血模型的定义方式。
封装应量力而行
虽然说 C++/Java 都是一种面向对象的语言,如果写过 Java Web 的话,会习惯性的各种封装以贴合 MVC 模式,C++ 就不是非常的在意这一套了,能使用基本参数的,几乎都会以基本参数优先。(如果参数多于 6 个再考虑将这些参数封装成类进行传递)。
void query(uint64_t stu_id, std::string name)
// do something
C++ 大概会写成上述这样,但是 Java 更侧重下述写法。
public class StuModel
int id;
String name;
public void query(StuModel model)
// do something
异常可没那么流行
C++ 提供了异常机制,不过大家并不怎么会使用它。C++ 中一般返回错误码的形式来处理考虑不周到的情况,
Errorcode test()
// some function
if (error)
return Errorcode::FAILED_MSG;
return Errorcode::OK;
C++ 一般习惯上述写法,但是对于 Java 一般习惯下述写法。
public void test()
try
// some functions
catch (RunTimeException e)
throw new ByteDanceCustomException("error cause", e);
不兴 get/set 函数
Java 中对于类的属性一般会定义为私有,然后调用 get/set 函数来对其访问,但是 C++ 一般会直接将该属性定义为公有。
class Stu
public:
uint64_t id;
std::string name;
Stu stu;
stu.id = 1;
stu.name = "zhang"
std::cout << stu.id << stu.name << std::endl;
C++ 会写成上述形式,但是 Java 更侧重写成下述形式。
public class Stu
public getId()
return id;
public setId(int id)
this.id = id;
...
private int id;
private String name;
Stu stu = new Stu();
stu.setId(1);
System.out.println(stu.getId() + stu.getName());
构造函数不添加初始化逻辑
Java 的构造函数中一般会添加不少的初始化逻辑,在开源的项目中经常能看到这样的写法。C++ 当然也可以这么写,但是大家平时不会这么写。
class Encrypto
public:
Encrypto() = default;
Init();
// Encrypto encrypto;
// encrypto.Init();
C++ 大概会按照上述方式写,Java 则会按照下述方式写。
public class Encrypto
public Encrypto()
Init();
public void Init()
// do something
// Encrypto encrypto = new Encrypto();
链式编程并不受宠爱
C++ 并不喜欢链式编程,所以下述的写法是对的,但是大家很少这么写。
class Stu
public:
Stu id(uint64_t id)
this->id_ = id;
return *this;
Stu name(std::string name)
this->name_ = name;
return *this;
Stu age(uint32_t age)
this->age_ = age;
return *this;
private:
uint64_t id_;
std::string name_;
uing32_t age_;
// Stu stu;
// stu.id(1).name("bytedance").age(12);
Java 则比较喜欢下述写法,lombok 爱好者更甚。
public class Stu
public Stu()
public Stu id(int id)
this.id = id;
return this;
public Stu name(String name)
this.name = name;
return this;
public Stu age(int age)
this.age = age;
return this;
private int id;
private String name;
private int age;
// new Stu().id(1).name("bytedance").age(12);
以上是关于Java 转 C++ 那些事的主要内容,如果未能解决你的问题,请参考以下文章