6

为什么C++那么难?

 3 years ago
source link: https://zhuanlan.zhihu.com/p/262445116
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

为什么C++那么难?

一个人NB的不是标签

都2020年了,还要学C++吗?本文记录我学习C++的那些经历和心得。

C++好多理工科大学里面都有,它的学习难度比其他编程语言比如Python, Javascript, 和Java等等难。那为什么呢?

C++难的原因有三个基本点:

  • 提供抽象的同时也贴近硬件模型
  • Zero-overhead的抽象

贴近硬件模型,C++就要提供指针。指针对新手而言很难理解,但是它确实非常贴近硬件的。为什么呢?比如int* p; int i = *p. 取内容我们会写*p,看起来有点难看,但是实际上却对应着基本的汇编代码mov (p) $rax. 在硬件中,内容就是一串byte,C++很多model就是操作这些byte。读取成员变量,其实是根据相对this指针的偏移读取内存。

Zero-overhead:你不需要的不用付出代价,而你用到的,你不可能自己写得更好。包含:泛型,vptr, vtbl,手动管理内存(new, delete),undefined behavior。

兼容C:这是C++成功的一大原因,也是它语法用法难以理解的一大原因。

例子一

请问下面的代码能正确编译链接嘛?

//book.cpp
class Book {
public:
  static int Count;
  Book() = default;
  ~Book() = default;
}
int main() {
  Book::Count += 1;
}

答案是不能!class Book后面右花括号要有分号! 纳里?如果你写过Java,你会更吃惊!按我们的书写习惯,Book的右花括号已经可以表明类结束了。但是为了兼容C,分号必须要有。为什么呢?因为C里面可以书写下面的代码

struct Book {
} book;

这样子定义了一个名为book的Book变量。所以C++也需要在定义类的结尾时候书写分号。这个分号我无数次忘记,幸好现在的IDE比较智能,都会提示出来。

把分号添加了以后,我们能成功编译嘛?不能,因为不能成功连接。如果用下面的命令编译

g++ -std=c++11 book.cpp -o book

error是

Undefined symbols for architecture x86_64:
  "Book::Count", referenced from:
      _main in book-b5397d.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

!!??这又是为什么?那是因为 Count只是被声明了,而没有定义。在Java里面这个代码完全没有问题!我第一次写的时候,也吃惊(我之前写过Java。)最后是万能的Google帮忙解决了。这是因为C++区分声明和定义:声明是为了引入一个名字,定义是将名字赋予实体。

那如果我们直接初始化count为2呢?还是不行,得到的错误是

book.cpp:4:14: error: non-const static data member must be initialized out of
      line
  static int Count = 2;
             ^       ~
1 error generated.

错误提示我们要对count进行定义并且"out of line"。 啥叫out of line?比如在int main()前面初始化

//book.cpp
class Book {
public:
  static int Count;
  Book() = default;
  ~Book() = default;
};
int Book::Count = 2;
int main() {
  Book::Count += 1;
}

这么简单的代码,我们经过了这么多次修正才正确编译!直到现在,C++17终于意识到,我们也需要像Java那样简简单单在类中定义一个静态变量,引入了inline static variable。所以如果我们使用C++17,那么上面的代码可以写成

//book.cpp
class Book {
public:
  inline static int Count = 2;
  Book() = default;
  ~Book() = default;
};
int main() {
  Book::Count += 1;
}

例子二

下面的代码有什么错误?

//把Book 类拷贝到这里
class MyBook:public Book {
public:
  void print() { std::cout<<"my book\n";}
}
int main() {
   Book book = new MyBook();
}

例子三

遇到下面的问题,怎么入手

: undefined reference to symbol ‘AtlComPtrAssign’
libmylib.so: error adding symbols: DSO missing from command line
collect2: error: ld returned 1 exit status

例子四

程序crash了怎么看core dump? 这需要单独一篇文章。

例子五

三五规则(关于构造器和赋值)记得怎么写吗?

例子六

Segment Fault 是什么?

……

(日后再慢慢更新剩下的每一个例子,因为C++太难了!这会变成一篇很长的文章)


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK