gpt4 book ai didi

面向 C# 开发人员的 C++

转载 作者:行者123 更新时间:2023-12-01 19:20:45 27 4
gpt4 key购买 nike

我是 .NET 开发人员,在此之前使用过 VB6。我已经非常熟悉这些环境,并在垃圾收集语言的上下文中工作。但是,我现在希望通过 native C++ 增强我的技能,但发现自己有点不知所措。具有讽刺意味的是,这并不是我想象的初学者常见的绊脚石,因为我觉得我已经很好地掌握了指针和内存管理。对我来说有点困惑的事情更多的是:

  • 引用/使用其他库
  • 公开我的库供其他人使用
  • 字符串处理
  • 数据类型转换
  • 良好的项目结构
  • 要使用的数据结构(即,在 C# 中,我经常使用 List<T>,我在 C++ 中使用什么类似的方法?)

  • 几乎感觉就像根据您使用的 IDE,指南是不同的,所以我真的在寻找可能更通用的东西。或者在最坏的情况下,专注于使用 Microsoft 的编译器/IDE。另外,为了清楚起见,我不是在寻找有关一般编程实践(设计模式、代码完成等)的任何内容,因为我觉得我非常精通这些主题。

    最佳答案

    我知道你说你已经很好地掌握了指针和内存管理,但我仍然想解释一个重要的技巧。
    作为一般经验法则,永远不要在您的用户代码中添加 new/delete。

    每个资源获取(无论是同步锁、数据库连接还是一块内存或其他任何必须获取和释放的东西)都应该包装在一个对象中,以便构造函数执行获取,析构函数释放资源。该技术被称为 RAII ,并且基本上是避免内存泄漏的方法。习惯它。
    C++ 标准库显然广泛使用了它,因此您可以了解它在那里是如何工作的。在您的问题中略有跳跃,相当于 List<T>std::vector<T> ,它使用 RAII 来管理它的内存。你会像这样使用它:

    void foo() {

    // declare a vector *without* using new. We want it allocated on the stack, not
    // the heap. The vector can allocate data on the heap if and when it feels like
    // it internally. We just don't need to see it in our user code
    std::vector<int> v;
    v.push_back(4);
    v.push_back(42); // Add a few numbers to it

    // And that is all. When we leave the scope of this function, the destructors
    // of all local variables, in this case our vector, are called - regardless of
    // *how* we leave the function. Even if an exception is thrown, v still goes
    // out of scope, so its destructor is called, and it cleans up nicely. That's
    // also why C++ doesn't have a finally clause for exception handling, but only
    // try/catch. Anything that would otherwise go in the finally clause can be put
    // in the destructor of a local object.
    }

    如果我必须选择一个 C++ 程序员必须学习和接受的原则,那就是上面的。让作用域规则和析构函数为您工作。它们提供了编写安全代码所需的所有保证。

    字符串处理:
    std::string你的 friend 在那里吗?在 C 中,您将使用字符数组(或字符指针),但这些很讨厌,因为它们的行为不像字符串。在 C++ 中,您有一个 std::string 类,它的行为与您期望的一样。唯一要记住的是,“hello world”的类型是 char[12] 而不是 std::string。 (为了 C 兼容性),所以有时你必须将你的字符串文字(用引号括起来的东西,比如“hello world”)显式转换为 std::string 以获得你想要的行为:
    你仍然可以写
    std::string s = "hello world";

    因为 C 风格的字符串(比如文字,比如“hello world”)可以隐式转换为 std::string,但它并不总是有效:
    "hello"+ "world"不会编译,因为 + 运算符没有为两个指针定义。
    "hello worl"+ 'd' 然而,会编译,但它不会做任何明智的事情。
    它不会将 char 附加到字符串,而是将 char 的整数值(提升为 int),并将其添加到指针的值中。

    然而,std::string("hello worl") + "d"却如你所愿,因为左侧已经是一个 std::string,并且加法运算符重载以便 std::string 像你一样做'd 期望,即使右侧是 char* 或单个字符。

    关于字符串的最后一个注意事项:
    std::string 使用 char,它是一种单字节数据类型。也就是说,它不适用于 unicode 文本。
    C++ 提供了宽字符类型 wchar_t,它是 2 或 4 个字节,具体取决于平台,并且通常用于 unicode 文本(尽管在这两种情况下 C++ 标准都没有真正指定字符集)。一串 wchar_t 被称为 std::wstring。

    图书馆:

    他们根本不存在。
    C++ 语言没有库的概念,这需要一些时间来适应。
    它允许您#include 另一个文件(通常是扩展名为 .h 或 .hpp 的头文件),但这只是逐字复制/粘贴。预处理器简单地将两个文件组合在一起,从而产生所谓的翻译单元。多个源文件通常会包含相同的头文件,并且仅在某些特定情况下才有效,因此这一点是理解 C++ 编译模型的关键,这是众所周知的古怪。不像 C# 编译器那样编译一堆单独的模块,并在它们之间交换某种元数据,而是单独编译每个翻译单元,并将生成的目标文件传递给链接器,然后链接器尝试合并公共(public)位重新组合在一起(如果多个翻译单元包含相同的 header ,则您基本上在翻译单元之间复制了代码,因此链接器将它们合并回单个定义);)

    当然,有特定于平台的方法来编写库。在 Windows 上,您可以制作 .dll 或 .libs,区别在于 .lib 链接到您的应用程序,而 .dll 是一个单独的文件,您必须与应用程序捆绑在一起,就像在 .NET 中一样。在 Linux 上,等效的文件类型是 .so 和 .a,并且在所有情况下,您还必须提供相关的头文件,以便人们能够针对您的库进行开发。

    数据类型转换:

    我不确定你在那里寻找什么,但我觉得很重要的一点是,如下所示的“传统” Actor 是不好的:
    int i = (int)42.0f; 

    有几个原因。
    首先,它尝试按顺序执行几种不同类型的转换,您可能会对编译器最终应用的转换感到惊讶。第二,在搜索中很难找到,第三,它不够丑。通常最好避免强制转换,而在 C++ 中,为了提醒您这一点,它们变得有点难看。 ;)
    // The most common cast, when the types are known at compile-time. That is, if 
    // inheritance isn't involved, this is generally the one to use
    static_cast<U>(T);

    // The equivalent for polymorphic types. Does the same as above, but performs a
    // runtime typecheck to ensure that the cast is actually valid
    dynamic_cast<U>(T);

    // Is mainly used for converting pointer types. Basically, it says "don't perform
    // an actual conversion of the data (like from 42.0f to 42), but simply take the
    // same bit pattern and reinterpret it as if it had been something else). It is
    // usually not portable, and in fact, guarantees less than I just said.
    reinterpret_cast<U>(T);

    // For adding or removing const-ness. You can't call a non-const member function
    // of a const object, but with a const-cast you can remove the const-ness from
    // the object. Generally a bad idea, but can be necessary.
    const_cast<U>(T);

    正如您将注意到的,这些强制转换更加具体,这意味着如果强制转换无效,编译器可以给您一个错误(与传统语法不同,它只会尝试上述任何一种强制转换,直到找到一个有效的转换) ),它又大又冗长,允许您搜索它,并提醒您应尽可能避免使用它们。 ;)

    标准库:

    最后,回到数据结构,努力理解标准库。它很小,但用途广泛,一旦您学会了如何使用它,您就会处于一个更好的位置。

    标准库由几个非常不同的构建块组成(该库随着时间的推移有所积累。其中一部分是从 C 移植过来的。I/O 流库从一个地方采用,容器类及其相关功能被采用来自一个完全不同的库,并且设计明显不同。后者是通常被称为 STL(标准模板库)的一部分。严格来说,这是库的名称,稍加修改后被采用C++ 标准库。

    STL 是理解“现代 C++”的关键。它由三个支柱组成,容器、迭代器和算法。
    简而言之,容器公开迭代器,算法在迭代器对上工作。

    以下示例采用 int vector ,将每个元素加 1,并将其复制到链表中,仅作为示例:
    int add1(int i) { return i+1; } // The function we wish to apply

    void foo() {
    std::vector<int> v;
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
    v.push_back(5); // Add the numbers 1-5 to the vector

    std::list<int> l;

    // Transform is an algorithm which applies some transformation to every element
    // in an iterator range, and stores the output to a separate iterator
    std::transform (
    v.begin(),
    v.end(), // Get an iterator range spanning the entire vector
    // Create a special iterator which, when you move it forward, adds a new
    // element to the container it points to. The output will be assigned to this
    std::back_inserter(l)
    add1); // And finally, the function we wish to apply to each element
    }

    上面的样式需要一些时间来适应,但它非常强大和简洁。
    因为转换函数是模板化的,所以它可以接受任何类型作为输入,只要它们表现得像迭代器。这意味着该函数可用于组合任何类型的容器,甚至流或任何其他可以迭代的东西,只要迭代器被设计为与 STL 兼容。我们也不必使用开始/结束对。代替结束迭代器,我们可以传递一个指向第三个元素的迭代器,然后算法就会在那里停止。或者我们可以编写自定义迭代器,跳过所有其他元素,或者我们喜欢的任何其他元素。
    以上是三个支柱中每个支柱的基本示例。我们使用容器来存储我们的数据,但是我们用来处理它的算法实际上并不需要知道容器。它只需要知道它必须工作的迭代器范围。当然,这三个支柱中的每一个都可以通过编写新类来扩展,然后它们将与 STL 的其余部分一起顺利地工作。

    从某种意义上说,这与 LINQ 非常相似,因此既然您来自 .NET,您可能会看到一些类比。不过,STL 对应物更灵活一些,代价是语法稍微有点奇怪。 :)
    (正如评论中提到的,它也更有效。一般来说,STL 算法的开销为零,它们可以像手工编码的循环一样有效。这通常令人惊讶,但这是可能的,因为所有相关类型都在编译时(这是模板工作的要求),并且 C++ 编译器倾向于积极地内联。)

    关于面向 C# 开发人员的 C++,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/285723/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com