在UNSW转码一年,第四学期接触C++,有很多不适应的地方,记一点平时可能会忘的东西。
期末考试临时知识点备忘
Container
1. std::vector
std::vector 是一个动态数组,可以根据需要动态调整大小。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 #include <vector> #include <iostream> #include <ranges> int main () { std::vector<int > v; v.push_back (1 ); v.emplace_back (2 ); v.pop_back (); v.size (); v.capacity (); v[0 ]; v.at (0 ); v.clear (); v.begin (); v.end (); v.shrink_to_fit (); v.reserve (10 ); v.resize (5 ); std::ranges::sort (v); for (const auto & elem : v) { std::cout << elem << " " ; } std::cout << std::endl; }
2. std::queue
std::queue 是一个FIFO(先进先出)数据结构。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include <queue> #include <iostream> int main () { std::queue<int > q; q.push (1 ); q.push (2 ); q.pop (); q.front (); q.back (); q.empty (); q.size (); while (!q.empty ()) { std::cout << q.front () << " " ; q.pop (); } std::cout << std::endl; }
3. std::deque
std::deque 是一种双端队列,可以在两端高效地插入和删除元素。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include <deque> #include <iostream> int main () { std::deque<int > d; d.push_back (1 ); d.push_front (2 ); d.pop_back (); d.pop_front (); d.front (); d.back (); d.size (); d.clear (); d.resize (5 ); for (const auto & elem : d) { std::cout << elem << " " ; } std::cout << std::endl; }
4. std::map
std::map 是一种关联容器,存储键值对,所有元素按照键值排序。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include <map> #include <iostream> int main () { std::map<int , std::string> m; m.insert ({1 , "one" }); m[2 ] = "two" ; m.erase (1 ); m.find (2 ); m.size (); m.clear (); m.contains (2 ); for (const auto & [key, value] : m) { std::cout << key << ": " << value << std::endl; } }
5. std::set
std::set 是一种关联容器,存储唯一的键值,所有元素按照键值排序。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include <set> #include <iostream> int main () { std::set<int > s; s.insert (1 ); s.insert (2 ); s.erase (1 ); s.find (2 ); s.size (); s.clear (); s.contains (2 ); for (const auto & elem : s) { std::cout << elem << " " ; } std::cout << std::endl; }
6. std::unordered_map
std::unordered_map 是一种哈希表,存储键值对,元素无序。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include <unordered_map> #include <iostream> int main () { std::unordered_map<int , std::string> um; um.insert ({1 , "one" }); um[2 ] = "two" ; um.erase (1 ); um.find (2 ); um.size (); um.clear (); um.contains (2 ); for (const auto & [key, value] : um) { std::cout << key << ": " << value << std::endl; } }
7. std::unordered_set
std::unordered_set 是一种哈希表,存储唯一的键值,元素无序。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include <unordered_set> #include <iostream> int main () { std::unordered_set<int > us; us.insert (1 ); us.insert (2 ); us.erase (1 ); us.find (2 ); us.size (); us.clear (); us.contains (2 ); for (const auto & elem : us) { std::cout << elem << " " ; } std::cout << std::endl; }
8. std::string
std::string 是一个用于处理和存储字符序列的标准库容器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #include <string> #include <iostream> int main () { std::string str = "Hello, World!" ; std::string str2 ("C++23" ) ; str.size (); str.length (); str.empty (); str.clear (); str[0 ]; str.at (1 ); str.append (" Welcome!" ); str += " Enjoy!" ; str.insert (5 , " C++" ); str.erase (0 , 5 ); str.substr (0 , 5 ); str.find ("World" ); str.find_first_of ("aeiou" ); std::cout << str << std::endl; }
9. std::optional
std::optional 是 C++17 引入的一个模板,用于表示可能不存在的值。它是一个包装器,可以包含一个类型为 T 的值或者不包含任何值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include <optional> #include <iostream> std::optional<int > get_data (bool flag) { if (flag) return 123 ; else return {}; } void use_optional () { auto result = get_data (true ); if (result) { std::cout << "值存在: " << *result << std::endl; } else { std::cout << "值不存在" << std::endl; } }
10. std::shared_ptr
std::shared_ptr 是 C++ 标准库中的一个智能指针,它可以用来管理具有引用计数的动态分配的对象。当 std::shared_ptr 的最后一个实例被销毁时,其指向的对象也会被自动释放。
1 2 3 4 5 6 7 8 9 10 11 #include <memory> void example () { std::shared_ptr<int > p1 (new int (10 )) ; std::shared_ptr<int > p2 = p1; std::cout << *p1 << std::endl; std::cout << *p2 << std::endl; }
11. std::stringstream
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include <iostream> #include <sstream> #include <vector> #include <string> int main () { std::stringstream oss; oss << "Hello, world!" ; auto output = std::vector<std::string>{}; output.push_back (oss.str ()); for (const auto & str : output) { std::cout << str << std::endl; } return 0 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 std::string data = "100 100 100 100 100" ; std::stringstream ss (data) ;int num;std::vector<int > numbers; while (ss >> num) { numbers.push_back (num); } std::cout << "Number of integers: " << numbers.size () << std::endl; for (int n : numbers) { std::cout << n << " " ; }
迭代器iterator
constness-reverse.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 #include <iostream> #include <vector> int main () { std::vector<int > ages; ages.push_back (18 ); ages.push_back (19 ); ages.push_back (20 ); for (auto iter = ages.begin (); iter != ages.end (); ++iter) { (*iter)++; } for (auto iter = ages.cbegin (); iter != ages.cend (); ++iter) { } for (auto iter = ages.rbegin (); iter != ages.rend (); ++iter) { std::cout << *iter << "\n" ; } }
Vector、Deque 和 Array
这些序列容器提供随机访问迭代器 ,支持迭代器加减、比较和随机访问。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include <vector> #include <iostream> int main () { std::vector<int > vec = {1 , 2 , 3 , 4 , 5 }; for (auto it = vec.begin (); it != vec.end (); ++it) { std::cout << *it << " " ; } std::cout << std::endl; for (auto rit = vec.rbegin (); rit != vec.rend (); ++rit) { std::cout << *rit << " " ; } std::cout << std::endl; }
Map 和 Set
这些关联容器提供双向迭代器 。它们的迭代器不支持随机访问,但可以进行递增和递减操作。
1 2 3 4 5 6 7 8 9 10 11 #include <map> #include <iostream> int main () { std::map<std::string, int > mp = {{"one" , 1 }, {"two" , 2 }, {"three" , 3 }}; for (auto it = mp.begin (); it != mp.end (); ++it) { std::cout << it->first << ": " << it->second << std::endl; } }
Random Access Iterator
下标操作 (operator[]): 允许直接访问迭代器指向的元素的指定偏移位置的元素,就像使用数组一样。
1 2 3 std::vector<int > v = {10 , 20 , 30 , 40 , 50 }; auto it = v.begin ();std::cout << it[2 ];
迭代器加减整数:可以将迭代器加上或减去一个整数,移动到当前位置的前后指定位置。
1 2 3 std::vector<int > v = {10 , 20 , 30 , 40 , 50 }; auto it = v.begin () + 3 ; std::cout << *it;
两个迭代器之间的减法:计算两个迭代器之间的距离,结果是两个迭代器指向的元素之间的位置差。
1 2 3 4 std::vector<int > v = {10 , 20 , 30 , 40 , 50 }; auto it1 = v.begin ();auto it2 = v.end ();std::cout << (it2 - it1);
迭代器的比较:可以比较两个迭代器的位置关系。
1 2 3 4 5 6 std::vector<int > v = {10 , 20 , 30 , 40 , 50 }; auto it1 = v.begin ();auto it2 = v.begin () + 2 ;if (it1 < it2) { std::cout << "it1 在 it2 之前" ; }
Sample:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #include <iostream> #include <vector> int main () { std::vector<int > vec = {5 , 10 , 15 , 20 , 25 }; auto it = vec.begin (); std::cout << "First element: " << *it << std::endl; it += 2 ; std::cout << "Third element: " << *it << std::endl; std::cout << "Fourth element: " << it[1 ] << std::endl; auto it2 = vec.end (); std::cout << "Distance from start to end: " << (it2 - it) << std::endl; return 0 ; }
Class
成员访问控制 Member Access Control
This is how we support encapsulation and information hiding in C++
member-access.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class foo {public : foo (); protected : private : void private_member_function () ; int private_data_member_; public : };
构造函数 Constructor
constructor-basic.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include <iostream> class myclass {public : myclass (int i) { i_ = i; } int getval () { return i_; } private : int i_; }; int main () { auto mc = myclass { 1 }; std::cout << mc.getval () << "\n" ; }
This 指针
成员函数有一个额外的隐式参数,名为 this。
A member function has an extra implicit parameter, named this
This is a pointer to the object on behalf of which the function is called
A member function does not explicitly define it, but may explicitly use it
The compiler treats an unqualified reference to a class member as being made through the this pointer.
Generally we use a “_” suffix for class variables rather than a this-> to identify them
这是一个指向代表其调用函数的对象的指针:
成员函数没有明确定义它,但可以明确使用它。
编译器将对类成员的不合格引用视为通过 this 指针进行的。
通常,我们使用“_”后缀来标识类变量,而不是使用 this->。
this 是一个指向当前对象的常量指针,不能被修改。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #include <iostream> class myclass {public : myclass (int i) { this ->i_ = i; } int getval () { return this ->i_; } private : int i_; }; int main () { auto mc = myclass { 1 }; std::cout << mc.getval () << "\n" ; }
explicit 显式关键字
自定义类intvec:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 #include <vector> class intvec {public : intvec (std::vector<int >::size_type length) : vec_ (length, 0 ) {} explicit intvec (std::vector<int >::size_type length) : vec_(length, 0 ) { }private : std::vector<int > vec_; }; auto main () -> int { int const size = 20 ; intvec container1{ size }; intvec container2 = intvec{ size }; }
代码解析:
类定义 :intvec 类中包含一个私有成员 vec_,它是一个 std::vector<int> 类型。
构造函数 :该类有一个构造函数,可接受 std::vector<int>::size_type 类型的参数,用于初始化 vec_ 的大小和默认值。
显式构造函数 :使用关键字 explicit 修饰构造函数,防止隐式类型转换。
主函数 :
container1 使用构造函数初始化,直接使用花括号。
container2 使用显式的构造函数调用进行初始化。
container3(已注释)如果取消注释,将尝试隐式转换,但由于构造函数被声明为 explicit,所以这将引发编译错误。
Const 成员
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 #include <iostream> #include <string> class person {public : person (std::string const & name) : name_{ name } {} auto set_name (std::string const & name) -> void { name_ = name; } auto get_name () -> std::string const & { return name_; } private : std::string name_; }; auto main () -> int { person p1 { "Hayden" }; p1.set_name ("Chris" ); std::cout << p1.get_name () << "\n" ; person const p2 { "Hayden" }; }
静态多态(编译时多态)
静态多态通常是通过函数重载 和运算符重载 实现的。编译器在编译时期决定了使用哪个函数,这种决策是基于参数的数量和类型。
1 2 3 4 5 6 7 8 9 class Print {public : void display (int i) { std::cout << "整数:" << i << std::endl; } void display (double f) { std::cout << "浮点数:" << f << std::endl; } };
动态多态(运行时多态)
动态多态是通过虚函数 实现的。当一个类声明了虚函数,它允许派生类重写该函数。具体调用哪个函数是在程序运行时决定的,基于对象的实际类型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class Base {public : virtual void print () { std::cout << "这是基类的函数。" << std::endl; } }; class Derived : public Base {public : void print () override { std::cout << "这是派生类的函数。" << std::endl; } }; void function (Base& b) { b.print (); }
Templates 模板
1 2 3 4 5 6 7 8 9 10 11 12 template <typename T>T add (T a, T b) { return a + b; } std::remove_cvref_t <decltype (add (2 , 3 ))> sum1 = add (2 , 3 ); std::forward<decltype (add (2.5 , 3.5 ))> sum2 = add (2.5 , 3.5 ); int main () { int sum1 = add <int >(2 , 3 ); double sum2 = add <double >(2.5 , 3.5 ); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include <iostream> #include <array> template <typename T, int size>T findmin (const std::array<T, size> a) { T min = a[0 ]; for (int i = 1 ; i < size; ++i) { if (a[i] < min) min = a[i]; } return min; } int main () { std::array<int , 3> x{ 3 , 1 , 2 }; std::array<double , 4> y{ 3.3 , 1.1 , 2.2 , 4.4 }; std::cout << "x 的最小值 = " << findmin (x) << "\\n" ; std::cout << "y 的最小值 = " << findmin (y) << "\\n" ; }
database.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 #ifndef DATABASE_HPP #define DATABASE_HPP #include "record.hpp" #include "query.hpp" #include <algorithm> #include <ostream> #include <map> #include <iostream> #include <string> #include <sstream> #include <vector> namespace q2 { class database { public : database () = default ; ~database () = default ; auto insert (record const & r) -> void { records_.push_back (r); } auto count () const -> std::size_t { return records_.size (); } friend auto operator <<(std::ostream& os, database const & g) -> std::ostream& { for (auto it =g.records_.begin (); it != g.records_.end (); ++it){ os << (*it); } return os; } friend auto operator >>(std::istream& is, database& sm) -> std::istream& { auto r = record (); while (is >> r){ sm.insert (r); r = record (); } return is; } auto delete_matching (query const & q) -> std::size_t { return std::erase_if (records_, [&q](auto const & item){ return q.matches (item); }); } auto select (query const & q) const -> database { database n; std::for_each(records_.begin (), records_.end (), [&q, &n](auto const & item){ if (q.matches (item)){ n.insert (item); } }); return n; } private : std::vector<record> records_; }; } #endif
query.hpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 #ifndef QUERY_HPP #define QUERY_HPP #include <algorithm> #include <ostream> #include <map> #include <iostream> #include <regex> #include <string> #include <sstream> #include "record.hpp" namespace q2 { class record ; class query { public : virtual ~query () = default ; virtual auto clone () const -> query* { return new query (*this ); } auto virtual matches (record const &) const -> bool { return true ; }; }; class query_equals : public query { public : query_equals (std::string attr, std::string value): attr_ (attr), value_ (value){}; auto matches (const record& r) const -> bool override { if (r.has_attribute (attr_)){ return r.get_value (attr_) == value_; } return false ; } auto clone () const -> query_equals* override { return new query_equals (attr_, value_); } private : std::string attr_; std::string value_; }; class query_less_than : public query { public : query_less_than (std::string attr, std::string value): attr_ (attr), value_ (value){}; auto matches (const record& r) const -> bool override { if (r.has_attribute (attr_)){ return r.get_value (attr_) < value_; } return false ; } auto clone () const -> query_less_than* override { return new query_less_than (attr_, value_); } private : std::string attr_; std::string value_; }; class query_greater_than : public query { public : query_greater_than (std::string attr, std::string value): attr_ (attr), value_ (value){}; auto matches (const record& r) const -> bool override { if (r.has_attribute (attr_)){ return r.get_value (attr_) > value_; } return false ; } auto clone () const -> query_greater_than* override { return new query_greater_than (attr_, value_); } private : std::string attr_; std::string value_; }; class query_starts_with : public query { public : query_starts_with (std::string attr, std::string value): attr_ (attr), value_ (value){}; auto matches (const record& r) const -> bool override { if (r.has_attribute (attr_)){ auto s = r.get_value (attr_); auto reg = std::regex ("^" +value_); if (std::regex_search (s, reg)){ return true ; } } return false ; } auto clone () const -> query_starts_with* override { return new query_starts_with (attr_, value_); } private : std::string attr_; std::string value_; }; class query_and : public query{ public : query_and (query const & q1, query const & q2): q1_ (q1.clone ()), q2_ (q2.clone ()){}; auto matches (const record& r) const -> bool override { return q1_->matches (r) and q2_->matches (r); } auto clone () const -> query_and* override { return new query_and (*q1_, *q2_); } ~query_and (){ delete q1_; delete q2_; } private : query* q1_; query* q2_; }; class query_or : public query{ public : query_or (query const & q1, query const & q2): q1_ (q1.clone ()), q2_ (q2.clone ()){}; auto matches (const record& r) const -> bool override { return q1_->matches (r) or q2_->matches (r); } auto clone () const -> query_or* override { return new query_or (*q1_, *q2_); } ~query_or (){ delete q1_; delete q2_; } private : query* q1_; query* q2_; }; class query_not : public query{ public : query_not (query const & q1): q1_ (q1.clone ()){}; auto matches (const record& r) const -> bool override { return !q1_->matches (r); } auto clone () const -> query_not* override { return new query_not (*q1_); } ~query_not (){ delete q1_; } private : query* q1_; }; } #endif
record.hpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 #ifndef RECORD_HPP #define RECORD_HPP #include <algorithm> #include <ostream> #include <map> #include <iostream> #include <string> #include <sstream> namespace q2 { class record { public : record () {}; ~record () {}; auto get_value (std::string const & s) const -> std::string { auto iter = values_.find (s); if (iter != values_.end ()){ return iter->second; } return "" ; } auto has_attribute (std::string const & key) const -> bool { auto iter = values_.find (key); if (iter != values_.end ()){ return true ; } return false ; } auto count () const -> std::size_t { return values_.size (); } auto delete_attribute (std::string const & key) -> bool { if (has_attribute (key)){ values_.erase (key); return true ; } return false ; } auto set_value (std::string const & key, std::string const & val) -> void { values_[key] = val; } friend auto operator <<(std::ostream& os, record const & g) -> std::ostream& { os << "{\n" ; std::for_each(g.values_.begin (), g.values_.end (), [&os](auto const & iter){ os << string_replace (string_replace (iter.first, "!" , "!!" ), "=" , "!=" ) << "=" << string_replace (string_replace (iter.second, "!" , "!!" ), "=" , "!=" ) << std::endl; }); os << "}" << std::endl; return os; } friend auto operator >>(std::istream& is, record& sm) -> std::istream& { (void ) sm; for (std::string s; std::getline (is, s);){ if (s == "{" ){ continue ; } if (s == "}" ){ break ; } s = string_replace (s, "!!" , "!" ); auto p = s.find ("=" ); auto pp = s.find ("!=" ); while (pp == p-1 ){ p = s.find ("=" , p+1 ); pp = s.find ("!=" , p+1 ); } sm.set_value (string_replace (s.substr (0 , p), "!=" , "=" ), string_replace (s.substr (p+1 , s.size ()), "!=" , "=" )); } return is; } private : std::map<std::string, std::string> values_; static auto string_replace (std::string const & s, std::string const & target, std::string const & repl) -> std::string { auto ret = s; auto pos = ret.find (target); while (pos != std::string::npos){ ret.replace (pos, target.size (), repl); pos = ret.find (target, pos+repl.size ()); } return ret; } }; } #endif