在c ++中经常被误解的概念是什么?
C++不是带有类的C!
并且没有称为C/C++的语言.一切都从那里开始走下坡路.
那个C++ 确实有自动资源管理.
(大多数声称C++没有内存管理的人试图过多地使用new和delete方法,没有意识到如果他们允许C++自己管理资源,那么任务变得更加容易).
示例:(使用组合的API制作,因为我现在没有时间检查文档)
// C++ void DoSomething() { File file("/tmp/dosomething", "rb"); ... do stuff with file... // file is automatically free'ed and closed. } // C# public void DoSomething() { File file = new File("/tmp/dosomething", "rb"); ... do stuff with file... // file is NOT automatically closed. // What if the caller calls DoSomething() in a tight loop? // C# requires you to be aware of the implementation of the File class // and forces you to accommodate, thus voiding implementation-hiding // principles. // Approaches may include: // 1) Utilizing the IDisposable pattern. // 2) Utilizing try-finally guards, which quickly gets messy. // 3) The nagging doubt that you've forgotten something /somewhere/ in your // 1 million loc project. // 4) The realization that point #3 can not be fixed by fixing the File // class. }
自由函数也不错,因为它们不属于类 C++不仅仅是OOP语言,而是基于一整堆技术.
当人们说自由函数(名称空间和全局命名空间中的函数)是"C次的残骸"时,我已经听过多次,应该避免.恰恰相反.自由函数允许从特定类中分离函数并允许重用功能.如果函数不需要访问实现细节,也建议使用自由函数而不是成员函数 - 因为当更改类的实现以及其他优点时,这将消除级联更改.
这也反映在语言中:基于范围的for循环C++0x
(即将发布的下一个C++版本)将基于自由函数调用.它会得到通过调用free函数开始/结束迭代器begin
和end
.
分配和初始化之间的区别:
string s = "foo"; // initialisation s = "bar"; // assignment
初始化总是使用构造函数,赋值总是使用operator =
按降序排列:
确保释放已分配内存的指针
当析构函数应该是虚拟的
虚拟功能如何工作
有趣的是,没有多少人知道虚拟功能的全部细节,但似乎仍然可以完成工作.
我见过的最有害的概念是它应该被视为带有一些插件的C. 实际上,对于现代C++系统,它应该被视为一种不同的语言,而且我看到的大部分C++ - bashing都是基于"C with add-ons"模型.
提一些问题:
尽管您可能需要知道的区别delete
和delete[]
,你通常应该写都不是.使用智能指针和std::vector<>
.
事实上,你应该*
很少使用.对字符串使用std :: string.(是的,它的设计很糟糕.无论如何都要使用它.)
RAII意味着您通常不必编写清理代码.清理代码是糟糕的风格,并破坏概念性的地方.作为奖励,使用RAII(包括智能指针)可以免费为您提供许多基本的异常安全性.总的来说,它在某些方面比垃圾收集要好得多.
通常,类数据成员不应该public
通过使用getter和setter 来直接可见.有一些例外(例如点类中的x和y),但它们是例外,应该这样考虑.
最重要的一点是:没有像C/C++这样的语言.可以编写可以在任何一种语言下正确编译的程序,但是这些程序不是很好的C++,并且通常不是很好的C.自Stroustrup开始研究"C with Classes"以来,这些语言已经发生了分歧,现在不像永远.使用"C/C++"作为语言名称是用户不知道他或她在说什么的表面证据.适当使用的C++与Java或C#不同.
过度使用与多态无关的继承.大多数情况下,除非你真的使用运行时多态,组合或静态多态(即模板)更好.
在静态关键字这可能意味着三个不同的事情之一取决于其使用的地方.
它可以是静态成员函数或成员变量.
它可以是在命名空间范围内声明的静态变量或函数.
它可以是函数内声明的静态变量.
数组不是指针
它们是不同的.所以&array
不是指向指针的指针,而是指向数组的指针.在我看来,这是C和C++中最容易被误解的概念.你必须访问所有那些告诉我们传递二维数组的答案type**
!
这里有一些:
使用模板实现不带vtable的多态,àlaATL.
内存中的逻辑性const
与实际性const
.何时使用mutable
关键字.
致谢:谢谢你纠正我的错误,spoulson.
编辑:
这里有更多:
虚拟继承(不是虚拟方法):事实上,我根本不理解它!(那个,我的意思是我不知道它是如何实现的)
成员是对象的联合,其各自的类具有非平凡的构造函数.
这是C++中一个经常被遗忘的重要概念:
C++不应该像Java或C#这样的面向对象语言一样简单地使用.从STL中激发自己并编写通用代码.
鉴于这种:
int x = sizeof(char);
什么价值是X?
您经常听到的答案取决于对规范的理解程度.
初学者 - x是一个因为字符总是八位值.
中级 - 它取决于编译器实现,字符可以是UTF16格式.
专家 - x是一个并且始终是一个,因为char是内存的最小可寻址单位,而sizeof确定存储该类型实例所需的内存单元数.因此,在char为8位的系统中,32位值的sizeof为4; 但在char为16位的系统中,32位值的sizeof为2.
不幸的是,标准使用'byte'来指代一个内存单元,因为许多程序员认为'byte'是8位.
从c开始,c ++的初学者经典:
混淆delete
和delete[]
编辑:
使用C API时,所有经验水平中的另一个经典失败:
std::string helloString = "hello world"; printf("%s\n", helloString);
代替:
printf("%s\n", helloString.c_str());
它每周都发生在我身上.您可以使用流,但有时您必须处理类似printf的API.
C++是一种多范式语言.许多人严格地将C++与OOP联系起来.
指针.
取消引用指针.通过任何一个.
或->
&
需要指针时使用的地址.
通过&
在签名中指定a 来通过引用获取参数的函数.
指向指针***
或指针的指针void someFunc(int *& arg)
人们似乎经常混淆或不知道的一些事情:
指针,尤其是函数指针和多指针(例如int(*)(void*),void***)
const关键字和const正确性(例如,const char*,char*const和const char*const之间的区别是什么,以及void class :: member()const是什么意思?)
内存分配(例如,每个指针neweded都应删除,malloc/free不应与new/delete混合,何时使用delete []而不是delete,为什么C函数仍然有用(例如expand(),realloc( )))
范围(即您可以单独使用{}为变量名创建一个新范围,而不仅仅作为if的一部分,等等...)
切换语句.(例如,不理解他们可以优化(或在某些情况下更好)优于ifs链,不理解通过及其实际应用(循环展开作为示例)或存在默认情况)
调用约定(例如cdecl和stdcall之间的区别是什么,你将如何实现pascal函数,为什么它甚至重要?)
继承和多重继承,更一般地说,是整个OO范例.
内联汇编程序,通常是实现的,不是C++的一部分.
指向成员的指针和指向成员函数的指针.
非类型模板参数.
多重继承,尤其是虚拟基类和共享基础对象.
构造和破坏的顺序,构建中间基类的虚函数的状态.
铸造安全和可变尺寸.不,你不能sizeof(void *) == sizeof(int)
在可移植代码中假设(或任何其他类型,除非便携式头特别保证它).
指针算术.
标题和实现文件
这也是许多人误解的概念.如果函数定义在一侧的程序中多次出现而在类别定义在另一侧出现多次时,则会出现如何进入头文件及其导致链接错误的问题.
与这些问题非常相似的是为什么有头部防护是很重要的.
如果函数接受指向指针的指针,void*
仍然会执行它
我已经看到了void指针的概念经常被混淆.据信如果你有一个指针,你使用a void*
,如果你有一个指针指针,你使用a void**
.但是你可以而且应该在两种情况下使用void*
.A void**
没有a的特殊属性void*
.
这是一个特殊属性,void*
也可以为a指定一个指向指针的指针,当收回时,会收到原始值.
我认为关于C++最容易被误解的概念是它存在的原因以及它的目的是什么.它经常受到上面的攻击(Java,C#等)和下面的(C).C++能够在机器附近操作以处理计算复杂性和抽象机制来管理域复杂性.
NULL
始终为零.
许多人NULL
对地址感到困惑,并认为如果平台具有不同的空指针地址,则不一定为零.
但NULL
总是零,它不是一个地址.它是一个零常量整数表达式,可以转换为指针类型.