C++ 牛逼!

Posted 编程指北

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++ 牛逼!相关的知识,希望对你有一定的参考价值。

大家好,我是周六的小北。

我们都知道,C++是一门难学易用的语言。

难学在于就连他的创始人 Bjarne Stroustrup 都说自己有时候看不懂这门语言了。

长期玩 `C++`` 都有一种感觉,那就是总觉得这门语言学不完,不管你的水平多高,一定会有你不知道的黑魔法,关键在于你不知道自己不知道。

C++ 是一门支持多范式编程的语言,提供了四种相辅相成的编程思维模式:

  • object-based:基于对象
  • object-oriented: 面向对象
  • procedural-based: 面向过程
  • generic paradigm: 泛型编程

你可以用C++ 写出 C 风格的代码,也能写出 Java 似的面向对象代码,更能写出天书版的模板元编程。

每一种范式我认为都是正交的,你可以只掌握 C with class,丝毫不会影响你用 `C++`` 写出优秀的软件。

很多时候看知乎这种论坛上的大佬谈论 C++ 容易被整自闭,他们喜欢用模板元来炫技,很多新手看起来就会比天书。

比如如何快速判断一个元素是否在一个集合中?

这是我在内网看其它大佬给出的解法,使用了C++ 11 可变参数模板和折叠表达式:

template <typename T>
is(const T& target) {
    return false;
}
template <typename T, typename... Args>
inline bool IsContains(const T& target, const Args&... args) {
    return ((target == args) || ...);
}
// use
IsContains(12,3);  // false
IsContains("a""a""b""c"); // true

但是我们用 std::set 一样能达到相同的目的,只不过在集合元素少的情况下,这种写法看起来会更加的 "C++",也更加炫技。

C++ 里,你几乎找不到任何一件简单的事。

比如这段 Java 里最普通的代码:

public class Test {
  public void hello(String name) {
    System.out.println("hello " + name);
  }
}

C++ 里,刚看完语法的初学者可能会这样写:

class Test {
  public:
   void hello(std::string name) {
     std::cout << "hello " << name;
   }
}

这样虽然能运行,但是效率和规范上都不是最好的。

为啥呢?

这就涉及到 C++ 参数的传递方式,对于上面这种写法,属于值传递,需要额外的拷贝构造带来的开销。

所以你需要将参数改为引用传递:

void hello(std::string & name)

这样就行了吗?

NO!

由于hello函数内部不涉及到修改 name变量,所以你需要将引用参数用 const 修饰。

一方面可以显示的告诉调用者函数不会修改 name变量,更重要的是,如果不加 const,下面这种情况将会编译报错:

Test test;
const std::string name = "小北";
test.hello(name); // 编译报错
// 或是这种
test.hello("小北"// 编译报错

由于参数不是const,所以对于 const 变量作为参数将导致编译不过。

但是这种使用场景本身就是合理的,出现这样的错误,只能说明我们的类设计有问题。

所以你需要给参数加上 const:

这样就完了吗?

NO!

因为 hello 方法没有被 const 修饰,所以constTest 对象无法调用该方法。如:

const Test test;
test.hello("小北"); // 编译报错

hello 方法本身不会改变对象成员变量,const 的对象应该能调用呀,所以你得给 hello 方法加上 const 修饰符:

void hello(std::string &name) const {...}

就这么一个简单的方法,在 C++ 里你需要考虑这么多东西才能够完美的运行起来。

在对象生成构造方面,Java 只需要申明一个构造函数就好了。

但是在 C++ 有拷贝构造、拷贝赋值、移动构造、移动赋、析构函数。

每一个类你都需要去考虑是否能够移动,怎么移动,能否拷贝等等。

又比如指针和引用,在 C 中只有指针,Java 中只有引用,而 C++ 是既有指针又有引用,并且引用还区分左值引用、右值引用哦~

还有指针的引用,引用的指针等等,然后再和顶层 const、底层 const 这些结合起来,简直不要太舒服。

C++ 的过程你会体会到对性能和减少 overhead 的极致追求。

C++ 固然很难学,但对于没有编程经验的同学,只要不去深入编程语言里每个晦涩难懂的角落。

把注意力集中到 C++ 中最主流、核心的部分,还是可以在 3 个月内学会 C++ 的。

而对于已经有 CJava 等语言基础的同学则能更快的掌握 C++

C++ 进阶是需要不断在实践中去学习的。

C++ 每一次发布新版本都会被吐槽越来越复杂,但是其实每一个新特性的加入都是为了让 C++ 用起来更简单。

比如 C++11 的 range-for 循环:

for (int& x : v) ++x;

v 可以是任意一种容器,C 风格的循环可能是这样的:

for (int i=0; i < MAX; i++) ++v[i]; 

但是这样可能会有潜在的越界等错误,而 range-for循环则更加优雅和更具通用性。

对于即将到来的 C++20,又将会是像 C++11 一样,是一个“大版本”。

会有一些全新的特性被引入 C++

  • Concepts
  • Ranges
  • Modules
  • ...

C++ 这么复杂难学还能保持这么高生命力,离不开它广泛的应用场景,比如:

  • 桌面应用(如 Adobe PS、Chrome、Microsoft Office 全家桶等)
  • 大型网站后台(比如微信后台、Google 搜索引擎、搜狗等)
  • 游戏和游戏引擎开发(如 Unity)
  • 编译器(如 LLVM/Clang 、 GCC)解释器( V8 引擎、JVM 等)
  • 视觉和智能引擎(如 OpenCV、TensorFlow)
  • 存储、数据库(如 mysql 和 MongoDB、Rocksdb等)

学好 C++ 还有一个好处就是,你再也不怕学其它语言了,因为很多语言的语法,某种程度上来说都可以在 C++ 中找到。


预告:

不要错过更新哟~

以上是关于C++ 牛逼!的主要内容,如果未能解决你的问题,请参考以下文章

以下代码片段 C++ 的说明

C++ 代码片段执行

此 Canon SDK C++ 代码片段的等效 C# 代码是啥?

C++ 代码片段(积累)

我的Android进阶之旅NDK开发之在C++代码中使用Android Log打印日志,打印出C++的函数耗时以及代码片段耗时详情

什么是在 C++ 中获取总内核数量的跨平台代码片段? [复制]