【全文完】【Deep C (and C++)】深入理解C/C++(4)

2023-10-11 16:18
文章标签 c++ 深入 理解 deep 全文完

本文主要是介绍【全文完】【Deep C (and C++)】深入理解C/C++(4),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

译自Deep C (and C++) by Olve Maudal and Jon Jagger,本身半桶水不到,如果哪位网友发现有错,留言指出吧:)

 

总结一下第三讲,我们可以知道,相对于第一位候选者,第二位候选者在以下几个方面有更深的认识:

1、  C与C++的联系;

2、  多态方面的技术;

3、  如何正确的初始化一个对象;

4、  Rule of three;

5、  操作符new[]与操作符delete[]方面的知识;

6、  常用的命名约定。

 

接下来,我们将分享一下几个方面的知识:

1、  对象的生命周期;

2、  Rule of three;

3、  虚函数表。

 

先来看,恰当地进行对象初始化。赋值与初始化是不一样的。来看这段代码的输出:

struct A
{A() { puts("A()"); }A(int v) { puts("A(int)"); }~A() { puts("~A()"); }
};struct X
{X(int v) { a = v; }X(long v):a(v) { }A a;
};int main()
{puts("bad style");{X slow(int(2));}puts("good style");{X fast(long(2));}
}

代码输出为:

bad style
A()
A(int)
~A()
~A()
good style
A(int)
~A()

再看看对象的生命周期:

C++的一个基本原理是:对象消亡时候需要采取的操作,正好是对象创建时候所采取操作的逆操作。

看下面的代码:

struct A
{A() { puts("A()"); }~A() { puts("~A()"); }
};struct B
{B() { puts("B()"); }~B() { puts("~B()"); }
};struct C
{A a;B b;
};int main()
{C obj;
}

程序的输出是:

A()
B()
~B()
~A()

再看:

struct A
{A():id(count++){printf("A(%d)\n", id);}~A(){printf("~A(%d)\n", id);}int id;static int count;
};//原文是没有这句的,不过根据C++规范,static数据成员必须在类定义体外定义。
//谢谢yuxq100指出。
int A::count = 0;int main()
{A array[4];
}

程序输出:

 

A(0)
A(1)
A(2)
A(3)
~A(3)
~A(2)
~A(1)
~A(0)

仔细看着张图,也会有所收获:

 

接下来看看:the rule of three:

If a class defines a copy constructor, acopy assignment operator, or a destructor, then it should define all three.

如果一个类定义了拷贝构造函数、赋值操作符、析构函数中的一个,那么通常需要全部定义这仨函数。

如图示:


接下类看看虚函数表:

看一下这段代码,虚函数表的结构大概如何呢?

struct base
{virtual void f();virtual void g();int a,b;
};struct derived:base
{virtual void g();virtual void h();int c;
};void poly(base* ptr)
{ptr->f();ptr->g();
}int main()
{poly(&base());poly(&derived());
}

虚函数表结构如何呢?看图:


简单说明:派生类没有重载f函数,它继承了基类的f函数,因此,派生类的虚函数表的f函数指向基类的f函数。但是,因为派生类重载了g函数,因此,其虚函数表中的g指向自身的g函数。

 

那么这段代码呢?

struct base
{void f();virtual void g();int a,b;
};struct derived:base
{virtual void g();virtual void h();int c;
};void poly(base* ptr)
{ptr->f();ptr->g();
}int main()
{poly(&base());poly(&derived());
}

基类的f函数不是虚函数了,这个时候的虚函数表结构又如何呢?


越多的同事对他们所使用的语言有深入的认识,这对你有什么好处吗?我们不建议(也不实际)要求公司里所有的C/C++程序员都深入理解C/C++。但是你确实需要绝大部分的程序员真的在意他们的专业度,他们需要求知若渴,不断努力,争取不断的加深对语言本身的理解。正所谓:stay hungry,stay foolish:)

 

现在回过头了看着这两名开发者,也就是我们之前所一直说的候选者。

亲,你觉得这两名开发者之间最大的差别在哪?

关于语言的现有知识吗?   不是!!

是他们对于学习的态度!!

 

你最后一次上编程方面的课程是什么时候?

第一个候选者这样回答:你什么意思?我在大学里学习编程,现在我通过实践来学习。你想知道什么?

你:那么,你现在在阅读哪些书?

候选者:书?哦,我不需要书。在我需要的时候,我会在网上查询手册。

你:你会跟你的同事谈论编程方面的东西吗?

候选者:我觉得没有必要!!我比他们强多了,从他们身上学不到任何玩意!!

 

你貌似对C/C++了解的更多,怎么做到的?

第二个候选者:我每天都会学习一些新东西,我真的乐在其中:)

我偶尔也会在stackoverflow.com、comp.lang.c还有comp.lang.c++跟进一些讨论。

我还参加了一个当地的C/C++用户组,我们定期会举行一些讨论会,交流心得。

我看了很多的书,很多很多。你知道吗?James Grenning刚刚写了一本很不错的书:《Test-Driven Development in C》,很值得一看:)

[PS:貌似是:Test-DrivenDevelopment for Embedded C]

我偶尔会被允许拜访WG14W以及G21。

[PS:
ISO WG14:ISO C委员会,具体指JTC1/SC22/WG14 C语言技术工作小组,通常简写为WG14。    ISO WG21:ISO C++委员会,具体指JTC1/SC22/WG21 C++技术工作小组,通常简写成WG21。

此人很牛逼呀:)]

我还是ACCU的会员,这里的人对于编程都有专业精神。我订阅了Overload,CVu及accu的一些综述文章。

[PS:移步看看ACCU的网站,确实应该去看看:

ACCU is an organisation of programmers whocare about professionalism in programming and are dedicated to raising thestandard of programming.

]

候选者接着说:无论何时只要有有机会,我都会参加C/C++课程,倒不是因为跟老师能学到什么东西,而是因为通过和其他同学的讨论,能扩展我的知识面。

但也许最好的知识来源于密切地配合我的同事们工作,与他们交流,分享自己所知的同时,从他们身上学到更多的知识。

(我表示从第二个候选者那学到了很多东西:)

 

最后,概述:

l  编译器和链接器(连接程序)

l  声明和定义

l  活动帧

l  内存段

l  内存对齐

l  序点

l  求值顺序

l  未定义和未指定

l  优化

l  关于C++的一些玩意

l  对象的恰当初始化

l  对象的生命周期

l  虚函数表

l  以及一些关于专业精神和学习态度的话题

 

这个时候第一个候选者貌似有所领悟:

第一个候选者:啊?

你:有什么问题吗?

候选者:我真的热爱编程,但是我现在认识到我真的还远远说不上专业。对于如何更好的学习C/C++,您能给我一些建议吗?

 

你:首先,你必须认识到编程是一件持续学习的的过程。不管你掌握了多少,总有很多知识需要你去学习。其次,你还必须认识到,专业编程最重要的一点是,你必须和你的同事亲密合作。想想体育比赛中,没有人可以做到单凭个人就能赢得比赛。

候选者:好的,我需要好好反省。。。

你:但是话说回来,养成这么个习惯,偶尔去关注一下代码所生成的汇编语句。你会发现很多有意思的东西。使用debugger,一步步的跟踪你的代码,看看内存的使用情况,同时看看处理器到底在执行什么指令。

候选者:有什么关于C/C++的书、网站、课程或是会议值得推荐吗?

 

你:要学习更多的现代软件的开发方式,我推荐James Grenning写的Test-Driven Development for Embedded C(貌似还没有中文版)。想要更深入的学习C语言,可以参考Peter van/Der Linden的Expert C Programming(C专家编程),这本书虽然成作已经20多年了,但是书上的观点依然管用。对于C++,我推荐你从Scott Meyers的Effective C++(国内侯捷老师翻译了此书)以及Herb Sutter 和Andrei Alexandrescu的C++ coding standards(C++编程规范)。

此外,如果你有机会参加任何于此有关的课程,不要犹豫,参加!只要态度正确,你就可以从老师和其他学生那里学到很多东西。

最后,我建议加入一些C/C++的用户组织,投身于社区当中。具体来说,我非常推荐ACCU,他们很专注于C/C++编程。你知道吗?他们每年的春季都会在牛津大学举行为期一周的与此相关的会议,与会者是来自全世界专业程序员:)或许明年4月份我会在那遇见你?

 

候选者:谢谢:)

 

你:祝你好运:)

 

全文完。

这篇关于【全文完】【Deep C (and C++)】深入理解C/C++(4)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/189274

相关文章

C++使用栈实现括号匹配的代码详解

《C++使用栈实现括号匹配的代码详解》在编程中,括号匹配是一个常见问题,尤其是在处理数学表达式、编译器解析等任务时,栈是一种非常适合处理此类问题的数据结构,能够精确地管理括号的匹配问题,本文将通过C+... 目录引言问题描述代码讲解代码解析栈的状态表示测试总结引言在编程中,括号匹配是一个常见问题,尤其是在

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

C++初始化数组的几种常见方法(简单易懂)

《C++初始化数组的几种常见方法(简单易懂)》本文介绍了C++中数组的初始化方法,包括一维数组和二维数组的初始化,以及用new动态初始化数组,在C++11及以上版本中,还提供了使用std::array... 目录1、初始化一维数组1.1、使用列表初始化(推荐方式)1.2、初始化部分列表1.3、使用std::

C++ Primer 多维数组的使用

《C++Primer多维数组的使用》本文主要介绍了多维数组在C++语言中的定义、初始化、下标引用以及使用范围for语句处理多维数组的方法,具有一定的参考价值,感兴趣的可以了解一下... 目录多维数组多维数组的初始化多维数组的下标引用使用范围for语句处理多维数组指针和多维数组多维数组严格来说,C++语言没

c++中std::placeholders的使用方法

《c++中std::placeholders的使用方法》std::placeholders是C++标准库中的一个工具,用于在函数对象绑定时创建占位符,本文就来详细的介绍一下,具有一定的参考价值,感兴... 目录1. 基本概念2. 使用场景3. 示例示例 1:部分参数绑定示例 2:参数重排序4. 注意事项5.

使用C++将处理后的信号保存为PNG和TIFF格式

《使用C++将处理后的信号保存为PNG和TIFF格式》在信号处理领域,我们常常需要将处理结果以图像的形式保存下来,方便后续分析和展示,C++提供了多种库来处理图像数据,本文将介绍如何使用stb_ima... 目录1. PNG格式保存使用stb_imagephp_write库1.1 安装和包含库1.2 代码解

C++实现封装的顺序表的操作与实践

《C++实现封装的顺序表的操作与实践》在程序设计中,顺序表是一种常见的线性数据结构,通常用于存储具有固定顺序的元素,与链表不同,顺序表中的元素是连续存储的,因此访问速度较快,但插入和删除操作的效率可能... 目录一、顺序表的基本概念二、顺序表类的设计1. 顺序表类的成员变量2. 构造函数和析构函数三、顺序表

使用C++实现单链表的操作与实践

《使用C++实现单链表的操作与实践》在程序设计中,链表是一种常见的数据结构,特别是在动态数据管理、频繁插入和删除元素的场景中,链表相比于数组,具有更高的灵活性和高效性,尤其是在需要频繁修改数据结构的应... 目录一、单链表的基本概念二、单链表类的设计1. 节点的定义2. 链表的类定义三、单链表的操作实现四、

深入解析Spring TransactionTemplate 高级用法(示例代码)

《深入解析SpringTransactionTemplate高级用法(示例代码)》TransactionTemplate是Spring框架中一个强大的工具,它允许开发者以编程方式控制事务,通过... 目录1. TransactionTemplate 的核心概念2. 核心接口和类3. TransactionT

使用C/C++调用libcurl调试消息的方式

《使用C/C++调用libcurl调试消息的方式》在使用C/C++调用libcurl进行HTTP请求时,有时我们需要查看请求的/应答消息的内容(包括请求头和请求体)以方便调试,libcurl提供了多种... 目录1. libcurl 调试工具简介2. 输出请求消息使用 CURLOPT_VERBOSE使用 C