您好,欢迎使用 C++。许多人会说 C++ 对于初学者来说是一种糟糕的选择语言。好吧,我很久以前就开始使用 C++,直到今天我还在学习。我是 100% 自学成才的,我不具备当今人们在互联网上提供的大量信息以及可用的现代格式方面的优势。当我刚开始学习 C++ 时,互联网正处于蓬勃发展的阶段;但当时大多数网站几乎都是纯文本,即使是简单的图片或图形也需要一段时间才能加载到屏幕上,因为那是在Dial Up 的时代。今天,刚起步的人拥有这个网站、其他类似网站甚至 youtube 视频的优势。但是,我仍然喜欢尽我所能提供帮助,因为它不仅可以帮助您,还可以帮助我改进我已经学到的知识。 C++ 多年来一直在发展,所以我将在这里向您展示一个小型应用程序,我相信它模仿了您所描述的您正在尝试做的事情的行为。其中一些技术对于初学者来说有点先进,但是我认为新手早期学习这些概念是一个很好的选择。
-
Storage Types & Lifetime - C++ 中基本上有 4 种主要存储类型:Automatic、Dynamic、Static 和 Thread。我主要关注前 3 个。
-
Automatic: 它具有声明它的范围的生命周期,并且一旦该范围退出其右括号},它将自动被销毁
-
Dynamic: 由指针表示但用new 声明的内存,并且必须分别具有匹配的delete 或数组new[] 和delete[]。它们的寿命可以比声明它们的范围更长。它们将一直存在,直到调用匹配的 delete 为止。如果没有匹配的删除发生,这会导致内存泄漏、无效指针、悬空指针和引用以及未定义的行为。使用raw-pointers时需要特别小心;建议使用containers 或smart pointers。
-
Static: 这些通常位于global 命名空间和/或global filespace。如果在main.cpp 中声明了static,它将具有应用程序的生命周期和整个程序的范围。如果它们在其他 cpp 文件中声明,它们将具有该文件的范围,除非它们在某些 header 文件中声明,那么它们将具有其他翻译单元包含该标头的范围。它们类似于Automatic,因为它们会被自动销毁,但它们的不同之处在于它们只被初始化一次,保持它们的状态并且你只能拥有它们的一个实例。
- 有关不同类型存储分类的演示,您可以查看我之前对此Q/A 的回答。
-
Classes and Inheritance: - (我不会涉及Polymorphism)。
-
Classes:
-
Classes 和 Structs 是用户定义的数据类型。
- 两者的区别在于默认访问
- 默认情况下:
Structs 有Public Members & Classes 有Private Members
-
Class 或 Struct 的成员可以是任何内置类型、指向类型的指针、其他用户定义的数据类型以及方法或函数。
-
Member Variables 可以是任何Storage Type:Automatic、Dynamic、Static 和Thread,但是,成员函数通常是Automatic,但也可以是Static。如果您有 member variable,则它必须是 initialized 之外的 Class's Declaration 才能解析为 symbols。
- 默认情况下他们有
Constructors 和Destructors,但可以创建自己的自定义Constructor 或Destructor。您通常会看到人们通过他们的简称提及他们:ctor 和 dtor。
- 一个类可以继承另一个类。
-
Inheritance:
- 你有
Base或SuperClasses,你有Derived或ChildClasses
- 当
Inheriting 来自Base 类时,如果Base 类的ctor 是Public,这意味着您可以创建Base 和Derived Classes 的对象。有时您想要这种设计,但有时您不想要。
- 如果您不希望用户能够创建
Base Class 的实例,但能够创建 Derived Class 的实例,那么您需要做的就是确保 1st 它的ctor 是Protected。如果你声明它Private,那么即使你的Derived Classes 也不能访问它,因此它们不能被声明。 *2nd 你要确保你的Destructors - dtors 是Virtual;否则你会遇到销毁类的顺序问题。
- 一个
Base Class 可以有Member Functions 是Virtual 这意味着所有Derived Classes 必须Implement 那个Function。
-
Base Class 可以有 Member Functions 是 Purely Virtual,这与上面类似,但也阻止任何人声明此 Base Class 的实例,因为这使得 Base @987654422 @Abstract 这意味着这是一个界面的想法。
- 示例
VirtualFunction:virtual update();
- 例如
Purely Virtual:`virtual update() = 0;
-
Containers - (我将使用std::container,但我不会涉及任何Algorithms)
- 容器种类繁多,满足不同需求;这些容器有助于使您的程序保持简单、易于管理和调试、用户友好,并避免使用
basic C Arrays 来避免许多未来的麻烦。
- 有几种不同的类型,它们都有自己的用途和属性,我不会详细介绍它们的所有细节,因为您可以在网上找到大量关于它们的信息,但我会将它们标记并分组到它们的相似属性:分组为
Sequence Containers、Associative Containers和Unordered Containers,这些都属于std::namespace。分组之间的主要区别是:Sequence Containers 类似于arrays 和linked lists,Associative Containers 类似于binary trees,而Unordered Containers 类似于binary trees,只是它们不按顺序排列,它们被认为是hash tables。
-
Sequence: vector, dequeue, queue, list, forward_list, array
-
Associative: set, multiset, map, multimap
-
Unordered: unordered_set, unordered_multiset, unordered_map, unordered_multimap`
- 这些容器的强大之处在于能够快速遍历它们或根据您使用的容器快速插入和查找。另一个很好的功能是在内存管理过程中提供帮助。最后是无数的
algorithms 和 iterators 可以对它们进行处理。
- 有关
stl 的更多信息,我建议观看this youtube 系列Bo Qian
Smart Pointers 有几种不同的类型,但最重要的两个是std::shared_ptr<T> 和std::unique_ptr<T>。两者的主要区别在于shared 有一个reference count 来表示有多少对象可以访问它;这意味着它具有公共类型接口并且可以使用复制语义;另一方面,unique 一次只有1 owner,它可以转让所有权,但一旦转让,原所有者就不再有权访问它。您不能复制unique,但可以移动它们。这些智能指针有助于使用dynamic memory 和生命周期对象管理,以防止内存泄漏、无效指针、悬空指针和引用、未定义行为等。它们有助于最大限度地减少new 和delete 和@987654477 的使用@ & delete[] 分别。
现在您已经了解了在C++ 程序中经常看到的一些概念;现在,我将向您展示我根据我认为您正在尝试做的事情编写的简单应用程序:
#include <array>
#include <exception>
#include <memory>
#include <string>
#include <iostream>
class Person {
protected:
std::string name_;
int tasksCompleted_;
public:
const std::string& whoIs() const { return name_; }
int numberTasksCompleted() const { return tasksCompleted_; }
virtual void performTask() = 0;
protected:
explicit Person(const std::string& name) : name_{ std::move(name) } {}
virtual ~Person() = default;
};
class Bodine final : public Person {
private:
static int currentTask;
public:
explicit Bodine(const std::string& name = std::string("Bodine")) : Person(name) {}
virtual ~Bodine() = default;
virtual void performTask() { currentTask++; tasksCompleted_ = currentTask; }
};
int Bodine::currentTask = 0;
class Finn final : public Person {
private:
static int currentTask;
public:
explicit Finn(const std::string& name = std::string("Finn")) : Person(name) {}
virtual ~Finn() = default;
virtual void performTask() { currentTask++; tasksCompleted_ = currentTask; }
};
int Finn::currentTask = 0;
class Tycho final : public Person {
private:
static int currentTask;
public:
explicit Tycho(const std::string& name = std::string("Tycho")) : Person(name) {}
virtual ~Tycho() = default;
virtual void performTask() { currentTask++; tasksCompleted_ = currentTask; }
};
int Tycho::currentTask = 0;
int main() {
try {
std::array<std::shared_ptr<Person>, 3> people{
std::shared_ptr<Person>(new Bodine()),
std::shared_ptr<Person>(new Finn()),
std::shared_ptr<Person>(new Tycho())
};
// For each person in array
const int MAX_TASKS = 7;
int currentPerson = 0;
for (auto& p : people) {
std::cout << p->whoIs() << " has performed task #:\n";
while (p->numberTasksCompleted() < 7) {
p->performTask();
std::cout << p->numberTasksCompleted() << '\n';
if (p->numberTasksCompleted() == MAX_TASKS) {
currentPerson++;
if (currentPerson <= (people.size() - 1) ) {
std::cout << "It's your turn " << people[currentPerson]->whoIs() << " to do some tasks.\n";
}
break;
}
}
}
} catch( std::runtime_error& e ) {
std::cerr << e.what() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
-输出-
Bodine has performed task #:
1
2
3
4
5
6
7
Finn has performed task #:
1
2
3
4
5
6
7
Tycho has performed task #:
1
2
3
4
5
6
7
Link 以上程序。
我知道这有点难读;但请仔细查看应用程序以尝试查看它在做什么。您可以将其复制并粘贴到您自己的 IDE 中,然后尝试构建并运行它以查看它的实际效果。希望这能让您了解C++ 是什么。
-编辑-
关于上面的代码:它比它真正需要的要复杂一些。首先,您不会真正将单个人的身份视为自己的班级。我这样做只是为了演示inheritance 是什么。我选择使用std::array 而不是std::vector 主要是因为您的提案中有3 特定人员。如果您在编译时有未知数量的人,那么std::vector 将是正确使用的容器。您也不需要使用继承。此外,如果您查看3 派生的classes,则有很多duplicate 代码。我还使用了shared_ptrs 来展示如何使用它们,但在您的特定情况下不是必需的。我还在Derived Classes 中使用了static member variables 来显示static storage。
这是上述代码的简化版本,用于模仿您的行为。两个程序执行相同的任务,唯一的主要区别是:inheritance 与 purely virtual methods、static member storage、container type 和 dynamic memory 的使用通过使用 shared_ptr。
#include <exception>
#include <iostream>
#include <string>
#include <vector>
class Person {
private:
std::string name_;
int tasksCompleted_;
public:
explicit Person(const std::string& name) : name_(name), tasksCompleted_(0) {}
const std::string& whoIs() const { return name_; }
int numberTasksCompleted() const { return tasksCompleted_; }
void performTask() { tasksCompleted_++; }
};
int main() {
try {
std::vector<Person> people{
Person( "Bodine" ),
Person( "Finn" ),
Person( "Tycho" )
};
// For each person in array
const int MAX_TASKS = 7; // Don't like magic numbers!
int currentPerson = 0; // Needed variable
for (auto& p : people) {
std::cout << p.whoIs() << " has performed task #:\n";
while (p.numberTasksCompleted() < MAX_TASKS) {
p.performTask();
std::cout << p.numberTasksCompleted() << '\n';
if (p.numberTasksCompleted() == MAX_TASKS) {
currentPerson++;
if (currentPerson <= (people.size() - 1) ) {
std::cout << "It's your turn " << people[currentPerson].whoIs() << " to do some tasks.\n";
}
break;
}
}
}
} catch( std::runtime_error& e ) {
std::cerr << e.what() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
这是此版本程序的link!