├── code ├── data.txt ├── use_sales_data.txt ├── trace_self.cc ├── template_instant.h.gch ├── str.cpp ├── stringstream.txt ├── use_compare_template.cc ├── TemplateBuild.cc ├── enumerations.cc ├── pass_by_ref.cpp ├── func_match.cpp ├── move_define.cc ├── initialization_cpp11.cc ├── ConstRef.cc ├── compare_template.h ├── account.cc ├── count_calls.cpp ├── friend_declaration.cc ├── reference_qualifier.cc ├── constexpr.cc ├── exempt_inherit_member.cc ├── bool.cpp ├── default_constructor.cc ├── no_default_constructor.cc ├── function_base.cpp ├── modulus.cpp ├── range_for.cpp ├── use_ShowBackStageCls.cc ├── decltype_return_type.cpp ├── cmd_options.cpp ├── throw_int.cpp ├── namespace.cc ├── iterator_arithmetic.cpp ├── swap.cpp ├── TextQueryComplicated.txt ├── bitwise_op.cpp ├── custom_new_delete.h ├── vec.cpp ├── vector_array.cpp ├── template_static.cc ├── using_directive.cc ├── increment.cpp ├── ShowBackStageCls.h ├── use_weak_ptr.cc ├── gradecal.cpp ├── initializer_list.cpp ├── for.cpp ├── explict_cast.cc ├── return_func.cpp ├── use_container_adaptor.cc ├── do_while.cpp ├── Application.cc ├── union.cc ├── conditional_op.cpp ├── manipulator.cc ├── trailing_rttype.cpp ├── bind.cc ├── use_TextQueryComplicated.cc ├── name_hidden.cc ├── const_rvalue_reference.cc ├── use_unique_ptr.cc ├── assignment.cpp ├── while.cpp ├── break.cpp ├── local_class.cc ├── default_arguments.cpp ├── initialization.cpp ├── new_align.cc ├── template_instant.h ├── delete_derived_copy_control.cc ├── binary_search.cpp ├── use_TextQuery.cc ├── if.cpp ├── array_func.cpp ├── trace_self.h ├── private_virtual_orverride.cc ├── throw.cpp ├── prevent_copy.cc ├── rvalue_reference.cc ├── str_subrange.cpp ├── variadic_function.cpp ├── constexpr_class.cc ├── extern_c.cc ├── const_struct.cc ├── typeinfo.cc ├── deleter_func.cc ├── vectorpush.cpp ├── debug_tools.cpp ├── name_hidden2.cc ├── use_has_ptr2.cc ├── find_char.cpp ├── iterator.cpp ├── move_operation.cc ├── use_allocator.cc ├── order_of_init.cc ├── ShowBackStageCls.cc ├── sizeof_op.cpp ├── template_conversion.cc ├── RTTI.cc ├── BaseDerived.cc ├── TextQuery.h ├── class_copy_assignment.cpp ├── array.cc ├── bit_field.cc ├── pair.cc ├── vector_test.cpp ├── cstr.cpp ├── lvalue_assignment.cc ├── overload.cpp ├── template_forward.cc ├── new_array.cc ├── template_parameter.cc ├── iterator.cc ├── static_class_member.cc ├── class_member_pointer.cc ├── variadic_template.cc ├── switch.cpp ├── word_transform.cc ├── noexcept.cc ├── ptrarray.cpp ├── base_function_hide.cc ├── use_trace_self.cc ├── template_specialization.cc ├── template_member_templates.cc ├── namespace_class.cc ├── stringstream.cc ├── func_pointer.cpp ├── TextQuery.cc ├── Makefile ├── multiple_inheritance.cc ├── bitset.cc ├── Quote.cc ├── new_delete.cpp ├── protected_access.cc ├── newscreen_window_mgr.cc ├── use_has_ptr.cc ├── multiarray.cpp ├── lambda.cc ├── word_count.cc ├── use_shared_ptr.cc ├── function_table.cc ├── associative_container.cc ├── conversion_operator.cc ├── union_class.cc ├── func_return_type.cpp ├── screen_window_mgr.cc ├── TextQuery.txt ├── TextQueryComplicated.cc ├── use_string.cc ├── overview_of_algorithms.cc ├── random.cc ├── io_revisit.cc ├── message.cc ├── function_call_operator.cc ├── TextQueryComplicated.h ├── Disc_Quote.cc ├── StrVec.cc ├── tuple.cc ├── template.cc └── StrBlob.cc ├── .gitignore ├── docs ├── CH17_Specialized_Library_Facilities.md ├── CH00_Preface.md └── CH05_Statements.md └── toc.py /code/data.txt: -------------------------------------------------------------------------------- 1 | 42 65 95 100 39 67 95 76 88 76 83 92 76 93 101 2 | -------------------------------------------------------------------------------- /code/use_sales_data.txt: -------------------------------------------------------------------------------- 1 | 0-201-78345-X 3 20.00 2 | 0-201-78345-X 2 25.00 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.out 2 | *.exe 3 | *.o 4 | ._* 5 | *.stackdump 6 | 7 | **/build/* 8 | -------------------------------------------------------------------------------- /code/trace_self.cc: -------------------------------------------------------------------------------- 1 | #include "trace_self.h" 2 | 3 | unsigned TraceSelf::unique_ = 0; 4 | -------------------------------------------------------------------------------- /code/template_instant.h.gch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuenlungwang/cppprimer-note/HEAD/code/template_instant.h.gch -------------------------------------------------------------------------------- /code/str.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | std::string s1 = "hello " + "world " + std::string("\n"); 6 | } 7 | -------------------------------------------------------------------------------- /code/stringstream.txt: -------------------------------------------------------------------------------- 1 | morgan 2015552368 8625550123 2 | drew 9735550130 3 | lee 6095550132 2015550175 8005550000 4 | Hammer 18679909045 5 | -------------------------------------------------------------------------------- /code/use_compare_template.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "compare_template.h" 4 | 5 | int main() 6 | { 7 | std::cout << compare(1, 0) << std::endl; 8 | return 0; 9 | } 10 | -------------------------------------------------------------------------------- /code/TemplateBuild.cc: -------------------------------------------------------------------------------- 1 | #include "template_instant.h" 2 | 3 | void func(); 4 | 5 | template int compare(const int &, const int &); 6 | 7 | int main() 8 | { 9 | func(); 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /code/enumerations.cc: -------------------------------------------------------------------------------- 1 | 2 | enum Tokens { INLINE = 128, VIRTUAL = 129 }; 3 | 4 | void ff(Tokens); 5 | void ff(int); 6 | 7 | int main() 8 | { 9 | Tokens curTok = INLINE; 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /code/pass_by_ref.cpp: -------------------------------------------------------------------------------- 1 | void reset(int &i) 2 | { 3 | i = 0; 4 | } 5 | 6 | int main() 7 | { 8 | int i = 100; 9 | reset(i); 10 | //reset(100); //非法的,100是常量引用 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /code/func_match.cpp: -------------------------------------------------------------------------------- 1 | void f(); 2 | void f(int); 3 | void f(int &); 4 | void f(int,int); 5 | void f(double,double=3.14); 6 | 7 | int main() 8 | { 9 | //f(42, 2.56); 10 | int a = 0; 11 | f(a); 12 | } 13 | -------------------------------------------------------------------------------- /code/move_define.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template 4 | typename std::remove_reference::type&& move(T&& t) 5 | { 6 | return static_cast::type&&>(t); 7 | } 8 | -------------------------------------------------------------------------------- /code/initialization_cpp11.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class C 5 | { 6 | std::string s = "abc"; 7 | double d = 0; 8 | char *p {nullptr}; 9 | int y[5] {1,2,3,4}; 10 | public: 11 | C()=default; 12 | }; 13 | -------------------------------------------------------------------------------- /code/ConstRef.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class ConstRef { 5 | public: 6 | ConstRef(int ii); 7 | private: 8 | int i; 9 | const int ci; 10 | int &ri; 11 | }; 12 | 13 | ConstRef::ConstRef(int ii): i(ii), ci(ii), ri(i) 14 | { 15 | } 16 | -------------------------------------------------------------------------------- /code/compare_template.h: -------------------------------------------------------------------------------- 1 | #ifndef COMPARE_TEMPLATE_H__ 2 | #define COMPARE_TEMPLATE_H__ 3 | 4 | template 5 | int compare(const T &v1, const T &v2) 6 | { 7 | if (v1 < v2) return -1; 8 | if (v2 < v1) return 1; 9 | return 0; 10 | } 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /code/account.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | typedef double Money; 5 | std::string bal; 6 | 7 | class Account { 8 | public: 9 | Money balance() { 10 | return bal; 11 | } 12 | private: 13 | typedef double Money; 14 | Money bal; 15 | }; 16 | -------------------------------------------------------------------------------- /code/count_calls.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | size_t count_calls() 4 | { 5 | static size_t ctr = 0; 6 | return ++ctr; 7 | } 8 | 9 | int main() 10 | { 11 | for (size_t i=0; i != 10; ++i) 12 | std::cout << count_calls() << std::endl; 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /code/friend_declaration.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void f(); 4 | 5 | struct X { 6 | friend void f() { } 7 | X() { f(); } 8 | void g(); 9 | void h(); 10 | }; 11 | 12 | void X::g() { 13 | return f(); 14 | } 15 | 16 | void X::h() { 17 | return f(); 18 | } 19 | -------------------------------------------------------------------------------- /code/reference_qualifier.cc: -------------------------------------------------------------------------------- 1 | class Foo { 2 | public: 3 | Foo sorted() &&; //provide a reference qualifier on all or none of functions 4 | Foo sorted() const &; 5 | 6 | using Comp = bool(const int &, const int &); 7 | Foo sorted(Comp *); 8 | Foo sorted(Comp *) const; 9 | }; 10 | -------------------------------------------------------------------------------- /code/constexpr.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | constexpr int sz = 100; 4 | constexpr int new_sz() { return sz; } 5 | constexpr int foo = new_sz(); 6 | 7 | constexpr size_t scale(size_t cnt) { return new_sz() * cnt; } 8 | 9 | int i = 2; 10 | int a2[scale(2)]; 11 | /* constexpr */ size_t j = scale(i); 12 | -------------------------------------------------------------------------------- /code/exempt_inherit_member.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class Base { 4 | public: 5 | std::size_t size() const { return n; } 6 | private: 7 | std::size_t n; 8 | }; 9 | 10 | class Derived : private Base { 11 | public: 12 | using Base::n; 13 | protected: 14 | using Base::size; 15 | }; 16 | -------------------------------------------------------------------------------- /code/bool.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | int val = 100; 6 | if (val == true) 7 | { 8 | std::cout << "val == TRUE" << std::endl; 9 | } 10 | 11 | if (val) 12 | { 13 | std::cout << "TRUE" << std::endl; 14 | } 15 | 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /code/default_constructor.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class A { 4 | public: 5 | int a; 6 | unsigned b; 7 | }; 8 | 9 | int main() 10 | { 11 | for (int i=0; i<100; i++) { 12 | A obj; 13 | std::cout << obj.a << " x " << obj.b << std::endl; 14 | } 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /code/no_default_constructor.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class NoDefault { 5 | public: 6 | NoDefault(const std::string & = "") {} 7 | }; 8 | 9 | struct A { 10 | NoDefault my_mem; 11 | }; 12 | 13 | A a; 14 | 15 | struct B { 16 | B() {} 17 | NoDefault b_member; 18 | }; 19 | -------------------------------------------------------------------------------- /code/function_base.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int fact(int val); 4 | 5 | int fact(int val) 6 | { 7 | int ret = 1; 8 | while (val > 1) 9 | ret *= val--; 10 | return ret; 11 | } 12 | 13 | int main() 14 | { 15 | int n = fact(5); 16 | std::cout << "5! is " << n << std::endl; 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /code/modulus.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | int ival1 = 21/6; 6 | int ival = 42; 7 | double dval = 3.14; 8 | std::cout << (ival % 12) << std::endl; 9 | std::cout << (-21%-8) << " " << (-21/-8) << std::endl; 10 | std::cout << (21%-5) << " " << (21/-5) << std::endl; 11 | 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /code/range_for.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | std::vector v = {0,1,2,3,4,5,6,7,8,9}; 6 | for (auto &r : v) 7 | r *= 2; 8 | 9 | //like below 10 | for (auto beg = v.begin(), end = v.end(); beg != end; ++beg) 11 | { 12 | auto &r = *beg; 13 | r *= 2; 14 | } 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /code/use_ShowBackStageCls.cc: -------------------------------------------------------------------------------- 1 | #include "ShowBackStageCls.h" 2 | #include 3 | 4 | int main() 5 | { 6 | ShowBackStageCls sbsc("sbsc"); 7 | std::cout << "reference" << std::endl; 8 | ShowBackStageCls &rsbsc = sbsc; 9 | std::cout << "copy initialize" << std::endl; 10 | ShowBackStageCls sbsc2 = rsbsc; 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /code/decltype_return_type.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int odd[] = {1,3,5,7,9}; 4 | int even[] = {0,2,4,6,8}; 5 | 6 | decltype(odd) *arrPtr(int i) 7 | { 8 | return (i%2) ? &odd : &even; 9 | } 10 | 11 | int main() 12 | { 13 | auto ret = arrPtr(3); 14 | for (int n : *ret) 15 | std::cout << n << std::endl; 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /code/cmd_options.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char *argv[]) { 5 | std::cout << "argc: " << argc << std::endl; 6 | for (int i=0; i(argv[argc]) << std::endl; 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /code/throw_int.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | int score = 0; 6 | while (std::cin >> score) 7 | { 8 | try { 9 | if (score > 100 || score < 0) 10 | throw score; 11 | } catch (int score) { 12 | std::cerr << "Input invalid score!!" << std::endl; 13 | } 14 | } 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /code/namespace.cc: -------------------------------------------------------------------------------- 1 | namespace A { 2 | int i; 3 | 4 | namespace B { 5 | int i; 6 | int j; 7 | 8 | int f1() 9 | { 10 | int j; 11 | return i; 12 | } 13 | } 14 | 15 | int f2() { 16 | // error: j is not defined 17 | //return j; 18 | return i; 19 | } 20 | 21 | int j = i; 22 | } 23 | -------------------------------------------------------------------------------- /code/iterator_arithmetic.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | std::string s("some string"); 8 | auto mid = s.begin() + s.size() / 2; 9 | *mid = std::toupper(*mid); 10 | std::cout << s << std::endl; 11 | std::cout << (s.begin() < mid) << std::endl; 12 | std::cout << (mid - s.begin()) << std::endl; 13 | 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /code/swap.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void swap(int &v1, int &v2) 4 | { 5 | if (v1 == v2) 6 | return; 7 | int tmp = v1; 8 | v1 = v2; 9 | v2 = tmp; 10 | } 11 | 12 | int main() 13 | { 14 | int ival1 = 10, ival2 = 20; 15 | swap(ival1, ival2); 16 | std::cout << "ival1: " << ival1 << std::endl; 17 | std::cout << "ival2: " << ival2 << std::endl; 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /code/TextQueryComplicated.txt: -------------------------------------------------------------------------------- 1 | Alice Emma has long flowing red hair . 2 | Her Daddy says when the wind blows 3 | through her hair, it looks almost alive, 4 | like a fiery bird in flight. 5 | A beautiful fiery bird, he tells her, 6 | magical but untamed. 7 | "Daddy, shush, there is no such thing," 8 | she tells him, at the same time wanting 9 | him to tell her more. 10 | Shyly, she asks, "I mean, Daddy, is there?" 11 | -------------------------------------------------------------------------------- /code/bitwise_op.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | unsigned char bits = 0233; 6 | std::cout << ((int)bits) << std::endl; 7 | bits <<= 31; 8 | std::cout << ((int)bits) << std::endl; 9 | 10 | unsigned long quiz1 = 0UL; 11 | quiz1 |= (1UL<<27); 12 | quiz1 &= (~(1UL<<27)); 13 | bool status = quiz1 & (1UL<<27); 14 | 15 | std::cout << (10<42); 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /code/custom_new_delete.h: -------------------------------------------------------------------------------- 1 | #ifndef __CUSTOM_NEW_DELETE_H__ 2 | #define __CUSTOM_NEW_DELETE_H__ 3 | 4 | #include 5 | #include 6 | 7 | void *operator new(size_t size) 8 | { 9 | if (void *mem = malloc(size)) 10 | return mem; 11 | else 12 | throw std::bad_alloc(); 13 | } 14 | 15 | void operator delete(void *mem) noexcept(true) 16 | { 17 | free(mem); 18 | } 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /code/vec.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | std::vector vec(2); 7 | std::cout << vec[200] << std::endl; 8 | 9 | auto cnt = vec.size(); 10 | for (decltype(vec.size()) ix = 0; ix < vec.size(); ++ix, --cnt) 11 | vec[ix] = cnt; 12 | for (auto i : vec) 13 | std::cout << i << " "; 14 | std::cout << std::endl; 15 | 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /code/vector_array.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | int int_arr[] = {0,1,2,3,4,5}; 8 | std::vector vec(std::begin(int_arr), std::end(int_arr)); 9 | std::vector subVec(int_arr+1, int_arr+4); 10 | for (auto &i : subVec) 11 | { 12 | std::cout << i << " "; 13 | } 14 | std::cout << std::endl; 15 | 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /code/template_static.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template 4 | class Foo { 5 | public: 6 | static std::size_t count() 7 | { 8 | return ctr; 9 | } 10 | private: 11 | static std::size_t ctr; 12 | }; 13 | 14 | template 15 | std::size_t Foo::ctr = 0; 16 | 17 | int main() 18 | { 19 | Foo fi; 20 | auto ct = Foo::count(); 21 | ct = fi.count(); 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /code/using_directive.cc: -------------------------------------------------------------------------------- 1 | namespace cplusplus_primer { 2 | /* Many things */ 3 | } 4 | 5 | namespace primer = cplusplus_primer; 6 | 7 | namespace blip { 8 | int i = 16, j = 15, k = 23; 9 | } 10 | 11 | int j = 0; 12 | 13 | void manip() 14 | { 15 | using namespace blip; 16 | ++i; 17 | //error: ambiguous: global j or blip::j? 18 | //++j; 19 | ++ ::j; 20 | ++ blip::j; 21 | int k = 97; 22 | ++k; 23 | } 24 | -------------------------------------------------------------------------------- /code/increment.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | int i = 0; 8 | int *j = &++i; //在C中是非法的,C只返回右值 9 | 10 | std::string v("Advice: Brevity Can Be a Virtue"); 11 | auto pbeg = v.begin(); 12 | while (pbeg != v.end()) 13 | { 14 | char c = *pbeg++; 15 | if (!isspace(c)) 16 | std::cout << c << std::endl; 17 | } 18 | 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /code/ShowBackStageCls.h: -------------------------------------------------------------------------------- 1 | #ifndef __SHOW_BACKSTAGE_CLS__ 2 | #define __SHOW_BACKSTAGE_CLS__ 3 | 4 | #include 5 | 6 | class ShowBackStageCls { 7 | public: 8 | ShowBackStageCls(const std::string &objName = "default"); 9 | ShowBackStageCls(const ShowBackStageCls &rsh); 10 | ~ShowBackStageCls(); 11 | private: 12 | std::string prettyName(); 13 | std::string _objName; 14 | int _id; 15 | int static ref; 16 | }; 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /code/use_weak_ptr.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | auto p = std::make_shared(42); 7 | std::weak_ptr wp(p); 8 | //p.reset(); //reset p will delete object that it points to. 9 | std::cout << wp.expired() << std::endl; 10 | if (std::shared_ptr np = wp.lock()) 11 | { 12 | std::cout << "inside the if, np shares its object with p" << std::endl; 13 | } 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /code/gradecal.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | std::vector clusters(11, 0); 7 | unsigned grade; 8 | while (std::cin >> grade) 9 | { 10 | if (grade <= 100) 11 | { 12 | ++clusters[grade/10]; 13 | } 14 | } 15 | for (int cluster : clusters) 16 | { 17 | std::cout << cluster << " "; 18 | } 19 | std::cout << std::endl; 20 | 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /code/initializer_list.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void error_msg(std::initializer_list il) 6 | { 7 | for (auto &elem : il) { 8 | std::cout << elem << " "; 9 | } 10 | std::cout << std::endl; 11 | } 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | std::string expected = "expected", actual = "actual"; 16 | error_msg({"functionX", expected, actual}); 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /code/for.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | std::string s = "process characters"; 9 | for (decltype(s.size()) index = 0; 10 | index != s.size() && !isspace(s[index]); ++index) 11 | s[index] = toupper(s[index]); 12 | std::cout << s << std::endl; 13 | for (;;)break; 14 | std::vector v; 15 | for (int i; std::cin >> i;) 16 | v.push_back(i); 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /code/explict_cast.cc: -------------------------------------------------------------------------------- 1 | int main() 2 | { 3 | double d = 0; 4 | void *p = &d; 5 | auto dp = static_cast(p); 6 | const double *cdp = static_cast(dp); 7 | double *dp2 = const_cast(cdp); 8 | static_cast(dp2); 9 | 10 | double * const xdp3 = &d; 11 | double *dp3 = static_cast(xdp3); 12 | static_cast(dp3); 13 | double *dp4 = const_cast(xdp3); 14 | static_cast(dp4); 15 | 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /code/return_func.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using F = int(int*, int); 5 | using PF = int(*)(int*, int); 6 | 7 | PF f1(int); 8 | F* f2(int); 9 | 10 | int (*f1(int))(int*, int); 11 | auto f1(int) -> int(*)(int*, int); 12 | 13 | std::string::size_type sumLength(const std::string&, const std::string&); 14 | std::string::size_type largerLength(const std::string&, const std::string&); 15 | decltype(sumLength) *getFunc(const std::string&); 16 | 17 | int main() 18 | { 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /code/use_container_adaptor.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | std::stack> str_stk; 9 | 10 | std::stack intStack; 11 | for (size_t ix = 0; ix != 10; ++ix) 12 | intStack.push(ix); 13 | while (!intStack.empty()) { 14 | int value = intStack.top(); 15 | std::cout << value << std::endl; 16 | intStack.pop(); 17 | } 18 | 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /code/do_while.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | std::string rsp; 7 | do { 8 | std::cout << "please enter two values: "; 9 | int val1 = 0, val2 = 0; 10 | std::cin >> val1 >> val2; 11 | std::cout << "The sum of " << val1 << " and " << val2 12 | << " = " << val1 + val2 << "\n\n" 13 | << "More? Enter yes or no: "; 14 | std::cin >> rsp; 15 | } while(!rsp.empty() && rsp[0] != 'n'); 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /code/Application.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "template_instant.h" 6 | 7 | extern template class Blob; 8 | extern template int compare(const int &, const int &); 9 | 10 | void func() 11 | { 12 | std::list w = {"now", "is", "the", "time"}; 13 | Blob sa1(w.begin(), w.end()), sa2(w.begin(), w.end()); 14 | 15 | int ia[] = {0,1,2,3,4,5,6,7,8,9}; 16 | Blob a1(std::begin(ia), std::end(ia)); 17 | 18 | int i = compare(ia[0], ia[3]); 19 | } 20 | -------------------------------------------------------------------------------- /code/union.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // Objects of type Token have a single member, which could 4 | // be of any of the listed types. 5 | union Token { 6 | char cval; 7 | int ival; 8 | double dval; 9 | }; 10 | 11 | int main() 12 | { 13 | Token first_token = { 'a' }; 14 | Token last_token; 15 | Token *pt = new Token; 16 | 17 | last_token.cval = 'z'; 18 | pt->ival = 42; 19 | 20 | std::cout << last_token.ival << std::endl; // 122 21 | std::cout << pt->cval << std::endl; // * 22 | 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /code/conditional_op.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void f1(); 4 | void f2(); 5 | 6 | int main() 7 | { 8 | 1?f1():f2(); //求值有顺序 9 | int a = 12, b = 12; 10 | (1?a:b) = 13; //在任何可以返回左值时返回左值 11 | std::cout << "a: " << a << " b: " << b << std::endl; 12 | int grade = 100; 13 | std::cout << (grade<60?"fail":"pass"); 14 | std::cout << (grade<60)?"fail":"pass"; 15 | return 0; 16 | } 17 | 18 | void f1() 19 | { 20 | std::cout << "f1()" << std::endl; 21 | } 22 | 23 | void f2() 24 | { 25 | std::cout << "f2()" << std::endl; 26 | } 27 | -------------------------------------------------------------------------------- /code/manipulator.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | std::cout << "hi!" << std::endl; 6 | std::cout << "hi!" << std::flush; 7 | std::cout << "hi!" << std::ends; 8 | 9 | // all writes will be flushed immediately 10 | std::cout << std::unitbuf; 11 | // returns to normal buffering 12 | std::cout << std::nounitbuf; 13 | 14 | // ties cin to cout 15 | std::cin.tie(&std::cout); 16 | std::ostream *oldTie = std::cin.tie(nullptr); 17 | std::cin.tie(&std::cerr); 18 | std::cin.tie(oldTie); 19 | 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /code/trailing_rttype.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | auto func(int i) -> int(*)[10]; 5 | 6 | int main() 7 | { 8 | auto data = func(10); 9 | for (int i=0; i<10; ++i) { 10 | for (const auto &n : data[i]) { 11 | std::cout << n << " "; 12 | } 13 | std::cout << std::endl; 14 | } 15 | return 0; 16 | } 17 | 18 | auto func(int i) -> int(*)[10] 19 | { 20 | int (*ret)[10] = new int[i][10]; //new 是值初始化 21 | for (int j=0; j 2 | #include 3 | #include 4 | 5 | bool check_size(const std::string &s, std::string::size_type sz) 6 | { 7 | return s.size() >= sz; 8 | } 9 | 10 | std::ostream &print(std::ostream &os, const std::string &s, char c) 11 | { 12 | return os << s << c; 13 | } 14 | 15 | int main() 16 | { 17 | using namespace std::placeholders; 18 | auto check6 = std::bind(check_size, _1, 6); 19 | std::cout << check6("check") << std::endl; 20 | std::cout << check6("check6") << std::endl; 21 | std::bind(print, ref(std::cout), _1, ' '); 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /code/use_TextQueryComplicated.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "TextQueryComplicated.h" 4 | 5 | void runQueries(std::ifstream &infile); 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | if (argc < 2) 10 | { 11 | std::cout << "Usage: a.exe filename" << std::endl; 12 | exit(1); 13 | } 14 | 15 | std::ifstream infile(argv[1]); 16 | runQueries(infile); 17 | 18 | return 0; 19 | } 20 | 21 | void runQueries(std::ifstream &infile) 22 | { 23 | TextQuery tq(infile); 24 | Query q = Query("Alice") & Query("hair"); 25 | print(std::cout, q.eval(tq)) << std::endl; 26 | } 27 | -------------------------------------------------------------------------------- /code/name_hidden.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct Base { 4 | Base() : mem(0) { } 5 | int memfcn(); 6 | protected: 7 | int mem; 8 | }; 9 | 10 | struct Derived : Base { 11 | Derived(int i) : mem(i) { } 12 | int get_mem() { return mem; } 13 | int get_base_mem() { 14 | return Base::mem; 15 | } 16 | //int memfcn; 17 | int memfcn(int); 18 | protected: 19 | int mem; 20 | }; 21 | 22 | int 23 | main() 24 | { 25 | Derived d(42); 26 | std::cout << d.get_mem() << std::endl; 27 | std::cout << d.get_base_mem() << std::endl; 28 | d.Base::memfcn(); 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /code/const_rvalue_reference.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct s{}; 4 | 5 | void f(s&) 6 | { 7 | std::cout << "void f(s&)" << std::endl; 8 | } 9 | 10 | void f(const s&) 11 | { 12 | std::cout << "void f(const s&)" << std::endl; 13 | } 14 | 15 | void f(s &&) 16 | { 17 | std::cout << "void f(s &&)" << std::endl; 18 | } 19 | 20 | void f(const s&&) 21 | { 22 | std::cout << "void f(const s&&)" << std::endl; 23 | } 24 | 25 | const s g() 26 | { 27 | return s(); 28 | } 29 | 30 | int main() 31 | { 32 | s x; 33 | const s cx; 34 | f(s()); 35 | f(g()); 36 | f(x); 37 | f(cx); 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /code/use_unique_ptr.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "trace_self.h" 5 | 6 | int main() 7 | { 8 | std::unique_ptr p1; 9 | std::unique_ptr p2(new double(42.1)); 10 | 11 | std::unique_ptr p3(new std::string("Stegosaurus")); 12 | //std::unique_ptr p4(p3); 13 | //std::unique_ptr p5; 14 | //p5 = p3; 15 | std::unique_ptr p6(p3.release()); 16 | std::unique_ptr p7(new TraceSelf()); 17 | std::unique_ptr p8(new TraceSelf()); 18 | p7.reset(p8.release()); 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /code/assignment.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | int k = 0; 8 | k = 3.14159; 9 | int j = 3.14159; 10 | 11 | double d; 12 | d = {3.14159}; 13 | d = {}; 14 | std::cout << "Zero: " << d << std::endl; 15 | k = d = j; 16 | 17 | std::vector vi; 18 | vi = {0,1,2,3,4,5,6,7,8,9}; 19 | 20 | std::string s; 21 | s = {"abc"}; 22 | std::cout << "s: " << s << std::endl; 23 | 24 | std::string str1; 25 | str1 = {}; 26 | std::cout << "empty string: " << str1 << std::endl; 27 | 28 | int a[] = {}; 29 | 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /code/while.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | int count = 0; 7 | while (int i=100) 8 | { 9 | count++; 10 | if (count == 10) 11 | break; 12 | i++; 13 | std::cout << i << std::endl; 14 | } 15 | 16 | std::vector v; 17 | int i; 18 | while (std::cin >> i) 19 | v.push_back(i); 20 | auto beg = v.begin(); 21 | while (beg != v.end() && *beg >= 0) 22 | ++beg; 23 | if (beg == v.end()) { 24 | std::cout << "We know that all elements in v are greater than or equal to zero" 25 | << std::endl; 26 | } 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /code/break.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | std::string buf; 7 | while (std::cin >> buf && !buf.empty()) 8 | { 9 | switch(buf[0]) { 10 | case '-': 11 | for (auto it = buf.begin()+1; it != buf.end(); ++it) 12 | { 13 | if (*it == ' ') 14 | break; 15 | } 16 | break; 17 | } 18 | } 19 | std::string buff; 20 | while (std::cin >> buf && !buf.empty()) 21 | { 22 | if (buff[0] != '_') 23 | continue; 24 | //still here? the input starts with an underscore; process buf... 25 | } 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /code/local_class.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int a, val; 4 | void foo(int val) 5 | { 6 | static int si; 7 | enum Loc { a = 1024, b }; 8 | 9 | struct Bar { 10 | Loc locVal; 11 | int barVal; 12 | void fooBar(Loc l = a) 13 | { 14 | // barVal = val; // error: val is local to foo 15 | barVal = ::val; 16 | barVal = si; 17 | locVal = b; 18 | } 19 | }; 20 | } 21 | 22 | void foo() 23 | { 24 | class Bar { 25 | public: 26 | // declares class Nested 27 | class Nested; 28 | }; 29 | 30 | // definition of Nested 31 | class Bar::Nested {}; 32 | } 33 | 34 | int main() 35 | { 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /code/default_arguments.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | typedef std::string::size_type sz; 5 | std::string screen(sz ht, sz wid=80, char backgrnd='&'); 6 | 7 | sz wd = 80; 8 | std::string screen(sz ht=wd, sz wid, char backgrnd); 9 | 10 | sz ht_(); 11 | 12 | int main() 13 | { 14 | sz wd = 200; 15 | screen(); 16 | ::wd = 100; 17 | screen(); 18 | std::string screen(sz ht=90, sz wid=70, char backgrnd='*'); 19 | screen(); 20 | return 0; 21 | } 22 | 23 | sz ht_() { 24 | return 1; 25 | } 26 | 27 | std::string screen(sz ht, sz wid, char backgrnd) 28 | { 29 | std::cout << "ht: " << ht << " wid: " << wid << " backgrnd: " << backgrnd << std::endl; 30 | return ""; 31 | } 32 | 33 | -------------------------------------------------------------------------------- /code/initialization.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct foo { 4 | foo() = default; 5 | int a; 6 | }; 7 | 8 | struct bar { 9 | bar(); 10 | int b; 11 | }; 12 | 13 | bar::bar() = default; 14 | 15 | ////////////////////////////////////////////////////////////////////////// 16 | 17 | struct A 18 | { 19 | int i; 20 | A() {} 21 | }; 22 | 23 | struct B { 24 | A a; 25 | B():a() {} 26 | }; 27 | 28 | //全局变量执行 zero initialization 29 | B globalB; 30 | 31 | int main() 32 | { 33 | foo a{}; 34 | bar b{}; 35 | int c{}; 36 | std::cout << a.a << ' ' << b.b << ' ' << c << std::endl; 37 | std::cout << B().a.i << std::endl; 38 | std::cout << globalB.a.i << std::endl; 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /code/new_align.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define ALIGN 8 6 | 7 | class NXCls { 8 | public: 9 | NXCls(char a): a_(a) {} 10 | private: 11 | char a_; 12 | }; 13 | 14 | int main() 15 | { 16 | //clang: 由 new 返回的指针必定是与机器底层对齐一致的,在64位机器上测试通过 17 | std::vector ptrs; 18 | for (int i=0; i<10000; i++) { 19 | NXCls *ptr = new NXCls(i); 20 | ptrs.push_back(ptr); 21 | assert((reinterpret_cast(ptr) & (ALIGN-1)) == 0); 22 | printf("ptr: %#lx\n", reinterpret_cast(ptr)); 23 | } 24 | 25 | for (auto ptr : ptrs) { 26 | delete ptr; 27 | } 28 | 29 | printf("test: %#08x\n", 1); 30 | 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /code/template_instant.h: -------------------------------------------------------------------------------- 1 | #ifndef TEMPLATE_INSTANT_H__ 2 | #define TEMPLATE_INSTANT_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | //Member Templates of Class Templates 9 | template 10 | class Blob { 11 | public: 12 | template Blob(It b, It e); 13 | private: 14 | std::shared_ptr> data; 15 | }; 16 | 17 | template 18 | template 19 | Blob::Blob(It b, It e) : data(std::make_shared>(b, e)) 20 | {} 21 | 22 | template 23 | int compare(const T &v1, const T &v2) 24 | { 25 | if (std::less()(v1, v2)) return -1; 26 | if (std::less()(v2, v1)) return 1; 27 | return 0; 28 | } 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /code/delete_derived_copy_control.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class B { 4 | public: 5 | B(); 6 | }; 7 | 8 | class D : public B { 9 | public: 10 | D() = default; 11 | D(const D &d) : B(d) {} 12 | D(D &&d) : B(std::move(d)) {} 13 | D& operator=(const D &rhs); 14 | }; 15 | 16 | D& D::operator=(const D &rhs) 17 | { 18 | B::operator=(rhs); 19 | return *this; 20 | } 21 | 22 | //////////////////////////////////////////////////////////////// 23 | struct C { 24 | C(int) {} 25 | operator int() { 26 | return 42; 27 | } 28 | }; 29 | 30 | int 31 | main() 32 | { 33 | B b; 34 | D d; 35 | D d2(d); 36 | D d3(std::move(d)); 37 | 38 | 39 | C a(1); 40 | C c(a); 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /code/binary_search.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | std::string::const_iterator binarysearch(const std::string& str, char c) 6 | { 7 | auto beg = str.begin(), end = str.end(); 8 | auto mid = beg + (end-beg)/2; 9 | while (mid != end) 10 | { 11 | if (*mid < c) beg = mid+1; 12 | else if (*mid == c) return mid; 13 | else end = mid; 14 | mid = beg + (end-beg)/2; 15 | } 16 | return str.end(); 17 | } 18 | 19 | int main() 20 | { 21 | std::string text = "abcdefghijklmnopqrstuvwxyz"; 22 | auto it = binarysearch(text, 'k'); 23 | if (it != text.end()) 24 | { 25 | std::cout << "find: " << *it << std::endl; 26 | } 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /code/use_TextQuery.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "TextQuery.h" 4 | 5 | void runQueries(std::ifstream &infile); 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | if (argc < 2) 10 | { 11 | std::cout << "Usage: a.exe filename" << std::endl; 12 | exit(1); 13 | } 14 | 15 | std::ifstream infile(argv[1]); 16 | runQueries(infile); 17 | 18 | return 0; 19 | } 20 | 21 | void runQueries(std::ifstream &infile) 22 | { 23 | TextQuery tq(infile); 24 | while (true) 25 | { 26 | std::cout << "enter word to look for, or q to quit: "; 27 | std::string s; 28 | if (!(std::cin >> s) || (s == "q")) 29 | break; 30 | print(std::cout, tq.query(s)) << std::endl; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /code/if.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define MAX(a,b) (((a)>(b))?(a):(b)) 6 | #define MIN(a,b) (((a)<(b))?(a):(b)) 7 | 8 | int main() 9 | { 10 | std::vector scores = {"F","D","C","B","A","A++"}; 11 | int grade; 12 | while (std::cin >> grade) 13 | { 14 | std::string lettergrade; 15 | grade = MIN(MAX(50, grade), 100); 16 | lettergrade = scores[(grade-50)/10]; 17 | if (grade>60 && grade <100) 18 | { 19 | if (grade % 10 > 7) 20 | lettergrade += '+'; 21 | else if (grade % 10 < 3) 22 | lettergrade += '-'; 23 | } 24 | std::cout << lettergrade << std::endl; 25 | } 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /code/array_func.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void print(const int (&arr)[10]) { 5 | std::cout << sizeof(arr) << std::endl; 6 | for (auto &elem : arr) 7 | std::cout << elem << std::endl; 8 | } 9 | 10 | void print(const int *beg, const int *end) { 11 | while (beg != end) { 12 | std::cout << *beg++ << std::endl; 13 | } 14 | } 15 | 16 | void print(const int ia[], size_t size) 17 | { 18 | for (size_t i = 0; i != size; ++i) { 19 | std::cout << ia[i] << std::endl; 20 | } 21 | } 22 | 23 | int main() 24 | { 25 | int arr[10] = {}; 26 | print(arr); 27 | 28 | int j[] = {0, 1}; 29 | print(std::begin(j), std::end(j)); 30 | 31 | print(j, std::end(j)-std::begin(j)); 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /code/trace_self.h: -------------------------------------------------------------------------------- 1 | #ifndef TRACE_SELF_H__ 2 | #define TRACE_SELF_H__ 3 | 4 | #include 5 | 6 | class TraceSelf 7 | { 8 | public: 9 | TraceSelf() { 10 | id_ = ++unique_; 11 | std::cout << id_ << ": TraceSelf()" << std::endl; 12 | } 13 | ~TraceSelf() { 14 | std::cout << id_ << ": ~TraceSelf()" << std::endl; 15 | } 16 | TraceSelf(const TraceSelf &rhs) { 17 | id_ = ++unique_; 18 | std::cout << id_ << ": TraceSelf(const TraceSelf&)" << rhs.id_ 19 | << std::endl; 20 | } 21 | TraceSelf& operator=(const TraceSelf &rhs) { 22 | std::cout << id_ << ": operator=()" << rhs.id_ << std::endl; 23 | return *this; 24 | } 25 | private: 26 | unsigned id_; 27 | static unsigned unique_; 28 | }; 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /code/private_virtual_orverride.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class Base { 4 | public: 5 | int pbfunc(); 6 | private: 7 | virtual void prfunc(); 8 | }; 9 | 10 | class Derived : public Base { 11 | private: 12 | virtual void prfunc() override; 13 | }; 14 | 15 | int Base::pbfunc() { 16 | std::cout << "before call prfunc" << std::endl; 17 | prfunc(); 18 | std::cout << "after call prfunc" << std::endl; 19 | return 8; 20 | } 21 | 22 | void Base::prfunc() { 23 | std::cout << "base prfunc" << std::endl; 24 | } 25 | 26 | void Derived::prfunc() { 27 | std::cout << "derived prfunc" << std::endl; 28 | } 29 | 30 | int main(int argc, char *argv[]) { 31 | Base b{}; 32 | b.pbfunc(); 33 | 34 | std::cout << "==========================" << std::endl; 35 | 36 | Derived().pbfunc(); 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /code/throw.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class A 4 | { 5 | public: 6 | A(): a(0) 7 | { 8 | this->id = ++A::ref; 9 | std::cout << this->id << ": A() default constructor" << std::endl; 10 | } 11 | A(const A &rsh) { 12 | this->id = ++A::ref; 13 | this->a = rsh.a; 14 | std::cout << this->id << ": A(const A&) copy constructor" << std::endl; 15 | } 16 | ~A() 17 | { 18 | std::cout << this->id << ": ~A() destructor" << std::endl; 19 | } 20 | private: 21 | int a; 22 | int id; 23 | int static ref; 24 | }; 25 | 26 | int A::ref = 0; 27 | 28 | int main() 29 | { 30 | try { 31 | A a; 32 | throw a; 33 | } catch (A a) { 34 | std::cout << "Catch exception of a" << std::endl; 35 | } 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /code/prevent_copy.cc: -------------------------------------------------------------------------------- 1 | struct NoCopy { 2 | NoCopy() = default; 3 | NoCopy(const NoCopy&) = delete; 4 | NoCopy &operator=(const NoCopy&) = delete; 5 | ~NoCopy() = default; 6 | }; 7 | 8 | struct NoDtor { 9 | NoDtor() = default; 10 | ~NoDtor() = delete; 11 | }; 12 | 13 | class PrivateCopy { 14 | PrivateCopy(const PrivateCopy &); 15 | PrivateCopy& operator=(const PrivateCopy &); 16 | public: 17 | PrivateCopy() = default; 18 | ~PrivateCopy(); 19 | }; 20 | 21 | int main() 22 | { 23 | NoCopy nc1; 24 | //NoCopy nc2 = nc1; 25 | //nc2 = nc1; 26 | 27 | //static NoDtor nd; //错误!! 不能创建删除了析构函数的普通 28 | NoDtor *p = new NoDtor(); //依然可以动态分配这种对象 29 | //delete p; //错误!! 不能删除对象,其析构函数已经被删除了 30 | 31 | PrivateCopy pc1; 32 | //PrivateCopy pc2 = pc1; 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /code/rvalue_reference.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | int i = 42; 7 | int &r = i; 8 | int &&rr = std::move(i); 9 | //int &r2 = i * 42; 10 | int const &r3 = i * 42; 11 | int &&rr2 = i * 42; 12 | 13 | //int &&rr3 = rr2;//We cannot bind an rvalue reference to a variable defined 14 | //as an rvalue reference type. 15 | 16 | const int crr1 = 100; 17 | int &&rr4 = std::move(static_cast(crr1)); 18 | 19 | const int crr2 = 26; 20 | const int *crr2p = &crr2; 21 | int *rr2p1 = const_cast(crr2p); 22 | (*rr2p1) += 1; 23 | std::cout << "crr2: " << crr2 << std::endl; 24 | std::cout << "rr2p1: " << *rr2p1 << std::endl; 25 | //int *rr2p2 = static_cast(crr2p); 26 | 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /code/str_subrange.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | bool str_subrange(const std::string &str1, const std::string &str2); 5 | 6 | int main() 7 | { 8 | std::cout << str_subrange("return normal equality test", "eual") << std::endl; 9 | return 0; 10 | } 11 | 12 | bool str_subrange(const std::string &str1, const std::string &str2) 13 | { 14 | if (str2.size() > str1.size()) return false; 15 | auto head = str1.size() - str2.size(); 16 | bool issub = false; 17 | for (decltype(head) i=0; i<=head; ++i) { 18 | issub = true; 19 | for (decltype(head) j=0; j 2 | #include 3 | 4 | void simple_printf(const char*fmt, ...); 5 | 6 | int main() 7 | { 8 | simple_printf("dcff", 3, 'a', 1.99, 42.5); 9 | return 0; 10 | } 11 | 12 | void simple_printf(const char*fmt, ...) 13 | { 14 | va_list args; 15 | va_start(args, fmt); 16 | while (*fmt != '\0') { 17 | if (*fmt == 'd') { 18 | int i = va_arg(args, int); 19 | std::cout << i << std::endl; 20 | } else if (*fmt == 'c') { 21 | int c = va_arg(args, int); 22 | std::cout << static_cast(c) << std::endl; 23 | } else if (*fmt == 'f') { 24 | double d = va_arg(args, double); 25 | std::cout << d << std::endl; 26 | } 27 | ++fmt; 28 | } 29 | va_end(args); 30 | } 31 | -------------------------------------------------------------------------------- /code/constexpr_class.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class Debug { 4 | public: 5 | constexpr Debug(bool b = true): hw(b), io(b), other(b) {} 6 | constexpr Debug(bool h, bool i, bool o): 7 | hw(h), 8 | io(i), 9 | other(o) 10 | {} 11 | constexpr bool any() const { return hw || io || other; } 12 | void set_io(bool b) { io = b; } 13 | void set_hw(bool b) { hw = b; } 14 | void set_other(bool b) { hw = b; } 15 | private: 16 | bool hw; 17 | bool io; 18 | bool other; 19 | }; 20 | 21 | int main() 22 | { 23 | constexpr Debug io_sub(false, true, false); 24 | if (io_sub.any()) 25 | std::cerr << "Print appropriate error messages" << std::endl; 26 | constexpr Debug prod(false); 27 | if (prod.any()) 28 | std::cerr << "print an error message" << std::endl; 29 | } 30 | -------------------------------------------------------------------------------- /code/extern_c.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | extern "C" size_t strlen(const char *); 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | int strcmp(const char*, const char*); 10 | char* strcat(char*, const char*); 11 | 12 | #ifdef __cplusplus 13 | } 14 | #endif 15 | 16 | // f1 is a C function; 17 | // Its parameter is a pointer to a C function 18 | extern "C" void f1(void(*)(int)); 19 | 20 | // FC is a pointer to a C function 21 | extern "C" typedef void FC(int); 22 | 23 | // f2 is a C++ function with a parameter that is a pointer to a C function 24 | void f2(FC *); 25 | 26 | 27 | ////////////////////////////////////////////////// 28 | // Exporting Our C++ Functions to Other Languages 29 | 30 | // the calc function can be called from C programs 31 | extern "C" double calc(double dparm) { 32 | /* ... */ 33 | } 34 | -------------------------------------------------------------------------------- /code/const_struct.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct Data { 4 | int i; 5 | double d; 6 | int *pi; 7 | }; 8 | 9 | int main() 10 | { 11 | struct Data d = {1, 2.2}; 12 | d.i = 3; 13 | d.pi = new int{10}; 14 | std::cout << "i: " << d.i << " d: " << d.d << " pi: " << *d.pi << std::endl; 15 | const struct Data &rfd = d; 16 | //rfd.d = 5.5; 17 | const struct Data *pd = &d; 18 | //pd->d = 6.6; 19 | *pd->pi = 100; 20 | std::cout << "i: " << d.i << " d: " << d.d << " pi: " << *d.pi << std::endl; 21 | 22 | //需要强调的一点是:const 对象中依然有某些可变的部分,原因在虽然成员本身是 23 | //const 的,但成员可能指向是非 const 对象, 24 | //抑或成员的常量成员函数返回的值并不是 const 的 25 | const struct Data cnst_d = {1, 2.2, new int{20}}; 26 | std::cout << *cnst_d.pi << std::endl; 27 | *cnst_d.pi = 999; 28 | std::cout << *cnst_d.pi << std::endl; 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /code/typeinfo.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class Base { 5 | public: 6 | // Base class must make it's destructor as virtual 7 | virtual ~Base() {} 8 | }; 9 | 10 | class Derived : public Base {}; 11 | 12 | int main() { 13 | Derived derived; 14 | Base *bp = &derived; 15 | Derived *dp = dynamic_cast(bp); 16 | if (dp) 17 | { 18 | printf("bp dynamic cast to dp successfully.\n"); 19 | } 20 | 21 | Base *bp1 = new Base; 22 | Derived *dp1 = dynamic_cast(bp1); 23 | if (dp1) 24 | { 25 | printf("bp1 dynamic cast to dp1 successfully\n"); 26 | } 27 | 28 | if (typeid(*bp) == typeid(*dp)) { 29 | printf("*bp has same type with *dp\n"); 30 | } 31 | if (typeid(*bp) == typeid(Derived)) { 32 | printf("*bp has same type with Derived\n"); 33 | } 34 | 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /code/deleter_func.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct destination { 5 | }; 6 | 7 | struct connection { 8 | }; 9 | 10 | connection connect(destination *dest) 11 | { 12 | std::cout << "connect" << std::endl; 13 | return connection(); 14 | } 15 | 16 | void disconnect(connection con) 17 | { 18 | std::cout << "disconnect" << std::endl; 19 | } 20 | 21 | void end_connection(connection *p) 22 | { 23 | disconnect(*p); 24 | } 25 | 26 | void f(destination &d) 27 | { 28 | connection c = connect(&d); 29 | std::shared_ptr p(&c, end_connection); //p会自动关闭连接 30 | } 31 | 32 | void f2(destination &d) 33 | { 34 | connection c = connect(&d); 35 | //p会自动关闭连接 36 | std::unique_ptr p(&c, end_connection); 37 | } 38 | 39 | int main() 40 | { 41 | destination dest; 42 | f(dest); 43 | f2(dest); 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /code/vectorpush.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | std::vector v2; 8 | for (int i=0; i != 100; ++i) 9 | v2.push_back(i); 10 | for (decltype(v2.size()) i=0; i != v2.size(); ++i) 11 | std::cout << v2[i] << std::endl; 12 | std::vector text; 13 | std::string word; 14 | while(std::cin >> word) { 15 | text.push_back(word); 16 | } 17 | for (const std::string& str : text) 18 | { 19 | std::cout << str << " "; 20 | } 21 | std::cout << std::endl; 22 | std::vector v{1,2,3,4,5,6,7,8,9}; 23 | for (auto& i : v) 24 | { 25 | i *= i; 26 | } 27 | for (auto i : v) 28 | { 29 | std::cout << i << " "; 30 | } 31 | std::cout << std::endl; 32 | auto sz = v.size(); 33 | std::cout << "size of v: " << sz << std::endl; 34 | 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /code/debug_tools.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define THRESHOLD 20 6 | 7 | void print(const char ia[], size_t size) 8 | { 9 | #ifndef NDEBUG 10 | std::cout << __func__ << ": array size is " << size << std::endl; 11 | #endif 12 | } 13 | 14 | void assert_(bool condition) 15 | { 16 | if (!condition) { 17 | std::cerr << "Error: " << __FILE__ 18 | << " : in function " << __func__ 19 | << " at line " << __LINE__ << std::endl 20 | << " Compiled on " << __DATE__ 21 | << " at " << __TIME__ << std::endl 22 | << " Word read was" << std::endl; 23 | } 24 | } 25 | 26 | int main() 27 | { 28 | std::string word = "foo"; 29 | print(word.c_str(), word.size()); 30 | //assert(word.size() > THRESHOLD); 31 | assert_(word.size() > THRESHOLD); 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /code/name_hidden2.cc: -------------------------------------------------------------------------------- 1 | class Base { 2 | public: 3 | virtual int fcn(); 4 | }; 5 | 6 | class D1 : public Base { 7 | public: 8 | int fcn(int); 9 | virtual void f2(); 10 | }; 11 | 12 | class D2 : public D1 { 13 | public: 14 | int fcn(int); 15 | int fcn() override; 16 | void f2() override; 17 | }; 18 | 19 | int 20 | main() 21 | { 22 | Base bobj; 23 | D1 d1obj; 24 | D2 d2obj; 25 | Base *bp1 = &bobj, *bp2 = &d1obj, *bp3 = &d2obj; 26 | 27 | bp1->fcn(); //Base::fcn 28 | bp2->fcn(); //Base::fcn 29 | bp3->fcn(); //D2::fcn 30 | 31 | D1 *d1p = &d1obj; 32 | D2 *d2p = &d2obj; 33 | //bp2->f2(); //错误: Base 没有 f2() 函数 34 | d1p->f2(); 35 | d2p->f2(); 36 | 37 | Base *p1 = &d2obj; 38 | D1 *p2 = &d2obj; 39 | D2 *p3 = &d2obj; 40 | //p1->fcn(42); //错误: Base 没有 fcn(int) 函数 41 | p2->fcn(42); //D1::fcn(int) 42 | p3->fcn(42); //D2::fcn(int) 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /code/use_has_ptr2.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | //pointer-like 5 | class HasPtr { 6 | public: 7 | HasPtr(const std::string &s = std::string()): 8 | ps(new std::string(s)), i(0), use(new std::size_t(1)) 9 | {} 10 | HasPtr(const HasPtr &p): 11 | ps(p.ps), i(p.i), use(p.use) 12 | { ++*use; } 13 | HasPtr& operator=(const HasPtr &); 14 | ~HasPtr(); 15 | private: 16 | std::string *ps; 17 | std::size_t *use; 18 | int i; 19 | }; 20 | 21 | HasPtr::~HasPtr() 22 | { 23 | if (--*use == 0) { 24 | delete use; 25 | delete ps; 26 | } 27 | } 28 | 29 | HasPtr& HasPtr::operator=(const HasPtr &rhs) 30 | { 31 | if (this == &rhs) 32 | return *this; 33 | ++*rhs.use; 34 | if (--*use == 0) { 35 | delete use; 36 | delete ps; 37 | } 38 | use = rhs.use; 39 | ps = rhs.ps; 40 | i = rhs.i; 41 | return *this; 42 | } 43 | -------------------------------------------------------------------------------- /code/find_char.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | std::string::size_type find_char(const std::string &s, char c, 5 | std::string::size_type &occurs) 6 | { 7 | auto ret = s.size(); 8 | occurs = 0; 9 | for (decltype(ret) i = 0; i != s.size(); ++i) { 10 | if (s[i] == c) { 11 | if (ret == s.size()) 12 | ret = i; 13 | ++occurs; 14 | } 15 | } 16 | 17 | return ret; 18 | } 19 | 20 | int main() 21 | { 22 | std::string s = "the value of ctr will be the number of times o occurs," 23 | " and index will refer to the first occurrence if there is one." 24 | " Otherwise, index will be equal to s.size() and ctr will be zero"; 25 | decltype(s.size()) ctr; 26 | auto i = find_char(s, 'o', ctr); 27 | std::cout << "first occur: " << i << ", " 28 | << "count of occurrence: " << ctr << std::endl; 29 | find_char("Hello World!", 'o', ctr); 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /code/iterator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | std::string s("some string"); 9 | if (s.begin() != s.end()) 10 | { 11 | auto it = s.begin(); 12 | *it = toupper(*it); 13 | } 14 | std::cout << s << std::endl; 15 | for (auto it = s.begin(); it != s.end() && !isspace(*it); ++it) 16 | { 17 | *it = toupper(*it); 18 | } 19 | std::cout << s << std::endl; 20 | 21 | std::vector::iterator it; 22 | decltype(s.begin()) it2; 23 | std::vector::const_iterator it3; 24 | std::string::const_iterator it4; 25 | 26 | std::vector text; 27 | std::string line; 28 | while (std::getline(std::cin, line)) 29 | { 30 | if (!line.empty()) 31 | text.push_back(line); 32 | } 33 | for (auto it = text.cbegin(); it != text.cend() && !it->empty(); ++it) 34 | std::cout << *it << std::endl; 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /code/move_operation.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct X { 5 | int i; 6 | std::string s; 7 | }; 8 | 9 | struct hasX { 10 | X mem; 11 | }; 12 | 13 | struct Y { 14 | Y() = default; 15 | Y(const Y&) { 16 | std::cout << "copy constructor of Y" << std::endl; 17 | } 18 | Y& operator=(const Y&) 19 | { 20 | return *this; 21 | } 22 | ~Y() {} 23 | //Y(Y &&) = delete; 24 | }; 25 | 26 | struct hasY { 27 | hasY() = default; 28 | hasY(hasY &&) = default; 29 | hasY(hasY &hasy): mem(hasy.mem) {} 30 | Y mem; 31 | }; 32 | 33 | int main() 34 | { 35 | X x, x2 = std::move(x); 36 | hasX hx, hx2 = std::move(hx); 37 | 38 | std::cout << "~~~~~~~~~~~~" << std::endl; 39 | //当std::move无法调用移动构造函数时,将调用拷贝构造函数 40 | //而声明为 delete 的意思是:函数可见且可以被用于函数匹配,但是如果 41 | //被选为最佳匹配时,会抛出编译错误!! 42 | Y y, y2 = std::move(y); 43 | std::cout << "~~~~~~~~~~~~~" << std::endl; 44 | hasY hy, hy2 = std::move(hy); 45 | 46 | return 0; 47 | } 48 | -------------------------------------------------------------------------------- /code/use_allocator.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | std::allocator alloc; 9 | const int n = 10; 10 | std::string * const p = alloc.allocate(n); 11 | auto q = p; 12 | alloc.construct(q++); 13 | alloc.construct(q++, 10, 'c'); 14 | alloc.construct(q++, "hi"); 15 | 16 | std::cout << p[1] << std::endl; 17 | std::cout << p[2] << std::endl; 18 | 19 | while (q != p) 20 | alloc.destroy(--q); 21 | 22 | alloc.deallocate(p, n); 23 | 24 | std::vector vi{1,2,3,4,5,6,7,8,9}; 25 | std::allocator alloc2; 26 | int *p2 = alloc2.allocate(vi.size() * 2); 27 | int *q2 = std::uninitialized_copy(vi.begin(), vi.end(), p2); 28 | for (int i=0; i != vi.size(); i++) 29 | std::cout << p2[i] << std::endl; 30 | std::uninitialized_fill_n(q2, vi.size(), 42); 31 | for (int i=0; i != vi.size(); i++) 32 | std::cout << q2[i] << std::endl; 33 | 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /code/order_of_init.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | //It is a good idea to write constructor initializers in the 4 | //same order as the members are declared. Moreover, when possible, 5 | //avoid using members to initialize other members. 6 | class X { 7 | friend std::ostream& operator<<(std::ostream &os, const X &x); 8 | 9 | int i; 10 | int j; 11 | public: 12 | X(int val): i(val), j(val) { 13 | std::cout << "Call X(int)" << std::endl; 14 | } 15 | X(): X(0) { 16 | std::cout << "Call X()" << std::endl; 17 | } 18 | X &add(int ia = 1, int ja = 1); 19 | }; 20 | 21 | std::ostream& operator<<(std::ostream &os, const X &x) 22 | { 23 | os << "i: " << x.i << " j: " << x.j; 24 | return os; 25 | } 26 | 27 | X &X::add(int ia, int ja) 28 | { 29 | i += ia; 30 | j += ja; 31 | return *this; 32 | } 33 | 34 | int main() 35 | { 36 | X x; 37 | std::cout << x.add() << std::endl; 38 | std::cout << x.add(2, 3) << std::endl; 39 | std::cout << x.add(2) << std::endl; 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /code/ShowBackStageCls.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "ShowBackStageCls.h" 4 | 5 | std::string ShowBackStageCls::prettyName() 6 | { 7 | std::ostringstream os; 8 | os << this->_id << "(" << this->_objName << ")"; 9 | return os.str(); 10 | } 11 | 12 | ShowBackStageCls::ShowBackStageCls(const std::string &objName): 13 | _objName(objName) 14 | { 15 | this->_id = ++ShowBackStageCls::ref; 16 | std::cout << prettyName() 17 | << ": ShowBackstageCls() default constructor" 18 | << std::endl; 19 | } 20 | 21 | ShowBackStageCls::ShowBackStageCls(const ShowBackStageCls &rsh) 22 | { 23 | this->_id = ++ShowBackStageCls::ref; 24 | this->_objName = rsh._objName; 25 | std::cout << prettyName() 26 | << ": ShowBackstageCls(const ShowBackstageCls&) copy constructor" 27 | << std::endl; 28 | } 29 | 30 | ShowBackStageCls::~ShowBackStageCls() 31 | { 32 | std::cout << prettyName() 33 | << ": ShowBackstageCls() destructor" 34 | << std::endl; 35 | } 36 | 37 | int ShowBackStageCls::ref = 0; 38 | -------------------------------------------------------------------------------- /code/sizeof_op.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class Sales_data { 4 | public: 5 | int d; 6 | int count; 7 | double revenue; 8 | double price; 9 | }; 10 | 11 | constexpr size_t f() 12 | { 13 | return 100; 14 | } 15 | 16 | int main() 17 | { 18 | Sales_data data, *p = &data; 19 | std::cout << sizeof(data) << std::endl; 20 | std::cout << sizeof(Sales_data) << std::endl; 21 | std::cout << sizeof(p) << std::endl; 22 | std::cout << sizeof(*p) << std::endl; 23 | std::cout << sizeof data.revenue << std::endl; 24 | std::cout << sizeof Sales_data::revenue << std::endl; 25 | 26 | const char *pc = "I have a dream to learn c++ very well"; 27 | const char parr[] = "I have a dream to learn c++ very well"; 28 | std::cout << sizeof(*pc) << std::endl; 29 | std::cout << sizeof(parr) << std::endl; 30 | std::cout << sizeof(&parr) << std::endl; 31 | 32 | constexpr size_t sz = f(); 33 | char carr[sz]; 34 | std::cout << sizeof(carr) << std::endl; 35 | constexpr size_t csz = sizeof(carr)/sizeof(*carr); 36 | int arr2[csz]; 37 | return 0; 38 | } 39 | 40 | -------------------------------------------------------------------------------- /code/template_conversion.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | template T fobj(T a, T b) 6 | { 7 | return a; 8 | } 9 | template T fref(const T &a, const T &b) 10 | { 11 | return a; 12 | } 13 | 14 | //Argument types can differ but must be compatible 15 | template 16 | int flexibleCompare(const A &v1, const B &v2) 17 | { 18 | if (v1 < v2) return -1; 19 | if (v2 < v1) return 1; 20 | return 0; 21 | } 22 | 23 | template 24 | std::ostream &print(std::ostream &os, const T &obj) 25 | { 26 | return os << obj; 27 | } 28 | 29 | int main() 30 | { 31 | std::string s1("a value"); 32 | const std::string s2("another value"); 33 | fobj(s1, s2); 34 | fref(s1, s2); 35 | 36 | int a[10], b[42]; 37 | fobj(a, b); //Convert to pointer to first element 38 | //fref(a, b); //Array types don't match 39 | 40 | long lng = 0; 41 | flexibleCompare(lng, 1024); 42 | 43 | print(std::cout, 42); 44 | 45 | std::ofstream f("output.o"); 46 | print(f, 10); 47 | 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /code/RTTI.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define UNUSED(expr) do { (void)(expr); } while(0) 5 | 6 | class Base { 7 | friend bool operator==(const Base &, const Base &); 8 | public: 9 | protected: 10 | virtual bool equal(const Base &) const; 11 | }; 12 | 13 | class Derived : public Base { 14 | public: 15 | protected: 16 | bool equal(const Base &) const override; 17 | }; 18 | 19 | bool Base::equal(const Base &rhs) const 20 | { 21 | return true; 22 | } 23 | 24 | bool operator==(const Base &lhs, const Base &rhs) 25 | { 26 | return typeid(lhs) == typeid(rhs) && lhs.equal(rhs); 27 | } 28 | 29 | bool Derived::equal(const Base &rhs) const 30 | { 31 | auto r = dynamic_cast(rhs); 32 | UNUSED(r); 33 | return true; 34 | } 35 | 36 | int main() 37 | { 38 | int arr[10]; 39 | Derived d; 40 | Base *p = &d; 41 | std::cout << typeid(42).name() << ", " 42 | << typeid(arr).name() << ", " 43 | << typeid(std::string).name() << ", " 44 | << typeid(p).name() << ", " 45 | << typeid(*p).name() << std::endl; 46 | 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /code/BaseDerived.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class Base { 5 | public: 6 | static void statmem(); 7 | }; 8 | 9 | class Derived : public Base { 10 | void f(const Derived &derived_obj); 11 | }; 12 | 13 | void 14 | Base::statmem() 15 | { 16 | std::cout << "static Base::statmem()" << std::endl; 17 | } 18 | 19 | void 20 | Derived::f(const Derived &derived_obj) 21 | { 22 | std::cout << "Derived::f(const Derived &)" << std::endl; 23 | Base::statmem(); 24 | Derived::statmem(); 25 | derived_obj.statmem(); 26 | statmem(); 27 | } 28 | 29 | class D1 : public Base {}; 30 | class D2 : public D1 {}; 31 | 32 | class NoDerived final {}; 33 | class Last final : public Base {}; 34 | //class Bad : public NoDerived {}; //不能继承 final 类 35 | //class Bad2 : public Last {}; 36 | 37 | struct B { 38 | virtual void f1(int) const; 39 | virtual void f2(); 40 | void f3(); 41 | }; 42 | 43 | struct D3 : B { 44 | auto f1(int) const -> void override final; 45 | //void f2(int) override; 46 | //void f3() override; 47 | //void f4() override; 48 | }; 49 | 50 | struct D4 : D3 { 51 | //void f1(int) const override; 52 | void f2() override; 53 | }; 54 | -------------------------------------------------------------------------------- /code/TextQuery.h: -------------------------------------------------------------------------------- 1 | #ifndef __TEXT_QUERY_H__ 2 | #define __TEXT_QUERY_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | class QueryResult; 14 | 15 | class TextQuery { 16 | public: 17 | class QueryResult; 18 | using line_no = std::vector::size_type; 19 | explicit TextQuery(std::ifstream &); 20 | public: 21 | QueryResult query(const std::string &) const; 22 | private: 23 | std::shared_ptr> file; 24 | std::map>> wm; 25 | }; 26 | 27 | class TextQuery::QueryResult { 28 | friend std::ostream& print(std::ostream&, const QueryResult&); 29 | public: 30 | QueryResult(std::string s, 31 | std::shared_ptr> p, 32 | std::shared_ptr> f) 33 | : sought(s), 34 | lines(p), 35 | file(f) 36 | {} 37 | private: 38 | std::string sought; 39 | std::shared_ptr> lines; 40 | std::shared_ptr> file; 41 | }; 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /code/class_copy_assignment.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | class mystring { 5 | public: 6 | mystring() { 7 | std::cout << "mystring()" << std::endl; 8 | } 9 | /* explicit */ mystring(const char *s) 10 | { 11 | std::cout << "mystring(const char *s)" << std::endl; 12 | } 13 | mystring(const mystring &rlh) { 14 | std::cout << "mystring(const mystring &rlh)" << std::endl; 15 | } 16 | //需要明白的是:虽然下面的直接赋值的构建方式并没有调用拷贝构造函数 17 | //(这是编译器的优化)但,依然需要此拷贝构造函数可见,定义为 delete 18 | //将无法通过编译 19 | //mystring(const mystring &rlh) = delete; 20 | mystring& operator=(const mystring &rlh) 21 | { 22 | std::cout << "operator=(const mystring &rlh)" << std::endl; 23 | return *this; 24 | } 25 | }; 26 | 27 | 28 | int main(int argc, const char *argv[]) 29 | { 30 | std::cout << "~~~~~~~~~~~~~~~~~" << std::endl; 31 | mystring mys = "mys"; 32 | std::cout << "~~~~~~~~~~~~~~~~~" << std::endl; 33 | mys = "MYS"; 34 | std::cout << "~~~~~~~~~~~~~~~~~" << std::endl; 35 | mystring mys2 = mystring("mys2"); 36 | std::cout << "~~~~~~~~~~~~~~~~~" << std::endl; 37 | mystring mys3 = {"mys3"}; 38 | 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /code/array.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | const unsigned cnt = 5; 8 | constexpr unsigned sz = 42; 9 | 10 | int arr[cnt] = {190, 23, 54}; 11 | int sum = 0; 12 | for (int i : arr) 13 | { 14 | sum += i; 15 | } 16 | std::cout << "The sum is " << sum << std::endl; 17 | std::string bad[cnt]; 18 | for (int i=0; i> grade) 42 | { 43 | if (grade <= 100) 44 | ++scores[grade/10]; 45 | } 46 | for (auto i : scores) 47 | { 48 | std::cout << i << " "; 49 | } 50 | std::cout << std::endl; 51 | 52 | return 0; 53 | } 54 | -------------------------------------------------------------------------------- /code/bit_field.cc: -------------------------------------------------------------------------------- 1 | typedef unsigned int Bit; 2 | class File { 3 | Bit mode: 2; // mode has 2 bits 4 | Bit modified: 1; // modified has 1 bit 5 | Bit prot_owner: 3; // prot_owner has 3 bits 6 | Bit prot_group: 3; // prot_group has 3 bits 7 | Bit prot_world: 3; // prot_world has 3 bits 8 | public: 9 | enum modes { READ = 01, WRITE = 02, EXECUTE = 03 }; 10 | 11 | File &open(modes); 12 | void close(); 13 | void write(); 14 | bool isRead() const; 15 | void setWrite(); 16 | }; 17 | 18 | void File::write() 19 | { 20 | modified = 1; 21 | } 22 | 23 | void File::close() 24 | { 25 | if (modified) 26 | /* do nothing */; 27 | } 28 | 29 | File &File::open(File::modes m) 30 | { 31 | mode |= READ; 32 | if (m & WRITE) 33 | /* do nothing */; 34 | return *this; 35 | } 36 | 37 | inline bool File::isRead() const 38 | { 39 | return mode & READ; 40 | } 41 | 42 | inline void File::setWrite() 43 | { 44 | mode |= WRITE; 45 | } 46 | 47 | // That is realy not good, I am feeling very bad now, 48 | // My reMarkable paper tablet does not ship to me. 49 | // I waited 11 days, 11 days, 11 days, not good, you know, 50 | // I just feel I am in ice-hole. Could glory God help me? 51 | // I hate this day. 52 | -------------------------------------------------------------------------------- /code/pair.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | std::pair 7 | process(std::vector &v) 8 | { 9 | if (!v.empty()) { 10 | //return {v.back(), v.back().size()}; 11 | return std::make_pair(v.back(), v.back().size()); 12 | } else 13 | return std::pair(); 14 | } 15 | 16 | int main() 17 | { 18 | std::pair anon; 19 | std::pair word_count; 20 | std::pair> line; 21 | 22 | std::pair author{"James", "Joyce"}; 23 | 24 | std::pair foo(90, 'A'); 25 | std::pair bar(90, 'a'); 26 | 27 | if (foo == bar) 28 | std::cout << "foo and bar are equal\n"; 29 | if (foo != bar) 30 | std::cout << "foo and bar are not equal\n"; 31 | if (foo < bar) 32 | std::cout << "foo is less than bar\n"; 33 | if (foo > bar) 34 | std::cout << "foo is greater than bar\n"; 35 | if (foo <= bar) 36 | std::cout << "foo is less than or equal to bar\n"; 37 | if (foo >= bar) 38 | std::cout << "foo is grater than or equal to bar\n"; 39 | 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /code/vector_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | std::vector ivec(10, -1); 8 | std::vector ivec2(ivec); 9 | std::vector svec(10, "hi!"); 10 | std::vector > file; 11 | 12 | std::vector articles = {"a", "an", "the"}; 13 | for (std::string& ar : articles) 14 | { 15 | std::cout << ar << std::endl; 16 | } 17 | std::vector articles2 {std::string("b"), "bn", "been"}; 18 | for (std::string& ar : articles2) 19 | { 20 | std::cout << ar << std::endl; 21 | } 22 | 23 | int a = {5}; 24 | double b{6}; 25 | int c(7); 26 | std::cout << a << c << std::endl; 27 | 28 | std::vector ivec3(20); 29 | for (int n : ivec3) 30 | { 31 | std::cout << n << std::endl; 32 | } 33 | 34 | std::vector svec2{10, "hi"}; 35 | for (const std::string& ar : svec2) 36 | { 37 | std::cout << ar << std::endl; 38 | } 39 | std::vector v8{10}; 40 | for (const std::string& v : v8) 41 | { 42 | std::cout << v << std::endl; 43 | } 44 | std::vector v9{1, 2.0}; 45 | 46 | return 0; 47 | } 48 | -------------------------------------------------------------------------------- /code/cstr.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | char ca[] = {'C','+','+','i','c','d'}; 7 | std::cout << strlen(ca) << std::endl; 8 | 9 | std::string s1 = "A string example"; 10 | std::string s2 = "A different string"; 11 | if (s1 > s2) 12 | { 13 | std::cout << "s1 is bigger than s2" << std::endl; 14 | } 15 | 16 | const char ca2[] = "A different string"; 17 | const char ca1[] = "A string example"; 18 | const char *ptr1 = "A string example"; 19 | std::cout << "sizeof(ca1): " << sizeof(ca1) << std::endl; 20 | std::cout << "sizeof(ptr1): " << sizeof(ptr1) << std::endl; 21 | if (ca1 > ca2) 22 | { 23 | std::cout << "ca1 is bigger than ca2" << std::endl; 24 | } 25 | if (strcmp(ca1, ca2) > 0) 26 | { 27 | std::cout << "strcmp: ca1 is bigger than ca2" << std::endl; 28 | } 29 | std::string largeStr = "CAT! " + s1 + " " + s2; 30 | std::cout << "string: " << largeStr << std::endl; 31 | 32 | char largecstr[256]; 33 | strcpy(largecstr, ca1); 34 | strcat(largecstr, " "); 35 | strcat(largecstr, ca2); 36 | std::cout << "cstring: " << largecstr << std::endl; 37 | 38 | const char *str = s1.c_str(); 39 | 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /code/lvalue_assignment.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | class Foo { 6 | public: 7 | Foo& operator=(const Foo&) &; 8 | Foo& operator=(Foo &&) &&; 9 | //如果定义了任何移动构造函数或者移动赋值,那么合成的拷贝构造函数和拷贝赋值 10 | //将是 delete 的,用户必须得自己定义 11 | Foo(const Foo &f) = default; 12 | Foo() = default; 13 | Foo(Foo &&f): data(std::move(f.data)) 14 | { 15 | f.data.clear(); 16 | } 17 | 18 | void call() const &&; 19 | 20 | Foo sorted() &&; 21 | Foo sorted() const &; 22 | private: 23 | std::vector data; 24 | }; 25 | 26 | Foo& Foo::operator=(const Foo &rhs) & 27 | { 28 | return *this; 29 | } 30 | 31 | Foo& Foo::operator=(Foo &&rhs) && 32 | { 33 | return *this; 34 | } 35 | 36 | void Foo::call() const && 37 | { 38 | std::cout << "call the Foo::call()" << std::endl; 39 | } 40 | 41 | Foo Foo::sorted() && 42 | { 43 | sort(data.begin(), data.end()); 44 | return *this; 45 | } 46 | 47 | Foo Foo::sorted() const & 48 | { 49 | Foo ret(*this); 50 | sort(ret.data.begin(), ret.data.end()); 51 | return ret; 52 | } 53 | 54 | int main() 55 | { 56 | Foo().call(); 57 | Foo() = Foo(); 58 | Foo().sorted(); 59 | const Foo f; 60 | f.sorted(); 61 | return 0; 62 | } 63 | -------------------------------------------------------------------------------- /code/overload.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void print(const int*) {} 4 | //void print(const int[]) {} 5 | //void print(const int[10]) {} 6 | 7 | class Account {}; 8 | class Phone {}; 9 | class Name {}; 10 | class Record {}; 11 | 12 | Record lookup(const Account&) {} 13 | Record lookup(const Phone&) {} 14 | Record lookup(const Name&) {} 15 | // bool lookup(const Account&) {} 16 | 17 | const std::string &shorterString(const std::string &s1, const std::string &s2) 18 | { 19 | return s1.size()(s1), const_cast(s2)); 26 | return const_cast(ret); 27 | } 28 | 29 | std::string read() {} 30 | void print(const std::string &) {} 31 | void print(double) {} 32 | void print(int) {} 33 | void fooBar(int ival) 34 | { 35 | bool read = false; 36 | //std::string s = read(); 37 | void print(int); 38 | //print("Value: "); 39 | print(ival); 40 | print(3.14); 41 | } 42 | 43 | int main() 44 | { 45 | Account acct; 46 | Phone phone; 47 | Record r1 = lookup(acct); 48 | Record r2 = lookup(phone); 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /code/template_forward.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | template 6 | void flip2(F f, T1 &&t1, T2 &&t2) 7 | { 8 | f(std::forward(t2), std::forward(t1)); 9 | } 10 | 11 | void g(int &&i, int &j) 12 | { 13 | std::cout << i << " " << j << std::endl; 14 | } 15 | 16 | //////////////////////////////////////////////////////// 17 | // Sample implementation of std::forward 18 | 19 | // For lvalues (T is T&), take/return lvalue refs. 20 | // For rvalues (T is T), take/return rvalue refs. 21 | template 22 | T&& forward(T &¶m) 23 | { 24 | return static_cast(param); 25 | } 26 | 27 | // Sample implementation of std::move 28 | // For lvalues (T is T&), remove_reference generate T, return rvalue ref. 29 | // For rvalues (T is T), remove_reference do nothing, return rvalue ref. 30 | template 31 | typename std::remove_reference::type&& move(T &¶m) 32 | { 33 | //Under C++11, We could cast lvalue ref to rvalue ref 34 | return static_cast::type&&>(param); 35 | } 36 | 37 | // !!The confusion is about const and reference function template type parameter. 38 | 39 | int main() 40 | { 41 | int i = 100; 42 | flip2(g, i, 42); 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /code/new_array.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "trace_self.h" 5 | 6 | int main() 7 | { 8 | int *pia = new int[20]; 9 | 10 | //using arrT = int[42]; //since c++11 11 | typedef int arrT[42]; 12 | int *p = new arrT; 13 | delete [] p; 14 | 15 | int *pia1 = new int[10]; 16 | auto pia2 = new int[10](); 17 | 18 | std::string *psa1 = new std::string[10]; 19 | std::string *psa2 = new std::string[10](); 20 | 21 | auto pia3 = new int[10]{0,1,2,3,4,5,6,7,8,9}; 22 | //remaining elements are value initialized 23 | std::string *psa3 = new std::string[10]{"a", "an", "the", std::string(3,'x')}; 24 | 25 | char arr[0]; 26 | char *cp = new char[0]; 27 | delete [] cp; 28 | 29 | std::unique_ptr up(new TraceSelf[10]); 30 | TraceSelf *pts = up.release(); 31 | std::cout << "After unique_ptr release" << std::endl; 32 | delete [] pts; 33 | 34 | std::cout << "use unique_ptr for releaseing TraceSelf" << std::endl; 35 | std::unique_ptr up2(new TraceSelf[10]); 36 | for (size_t i=0; i != 10; ++i) 37 | up2[i] = TraceSelf(); 38 | 39 | std::shared_ptr sp(new int[10], [](int *p){ delete[] p; }); 40 | for (size_t i=0; i != 10; ++i) 41 | *(sp.get() + i) = i; 42 | 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /code/template_parameter.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | typedef double A; 5 | 6 | template 7 | void f(A a, B b) 8 | { 9 | A tmp = a; 10 | } 11 | 12 | template 13 | T calc(const T&, const T&); 14 | 15 | template 16 | U calc(const U&, const U&); 17 | 18 | template 19 | Type calc(const Type& a, const Type& b) 20 | { 21 | return a; 22 | } 23 | 24 | template 25 | typename T::value_type top(const T& c) 26 | { 27 | if (!c.empty()) 28 | return c.back(); 29 | else 30 | return typename T::value_type(); 31 | } 32 | 33 | // Default template arguments 34 | template > 35 | int compare(const T &v1, const T &v2, F f = F()) 36 | { 37 | if (f(v1, v2)) return -1; 38 | if (f(v2, v1)) return 1; 39 | return 0; 40 | } 41 | 42 | // Template Default Arguments and Class Templates 43 | template 44 | class Numbers { 45 | public: 46 | Numbers(T v = T()) : val(v) { } 47 | T getVal() { return val; } 48 | private: 49 | T val; 50 | }; 51 | 52 | int main() 53 | { 54 | bool i = compare(0, 42); 55 | Numbers lots_of_precision; 56 | Numbers<> average_precision; 57 | std::cout << average_precision.getVal() << std::endl; 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /code/iterator.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() 8 | { 9 | // int_it blocks console, comment it 10 | // std::istream_iterator int_it(std::cin); 11 | // std::istream_iterator int_eof; 12 | 13 | std::ifstream in("stringstream.txt"); 14 | std::istream_iterator str_it(in), str_eof; 15 | std::ostream_iterator out_str_it(std::cout, " "); 16 | while (str_it != str_eof) 17 | *out_str_it++ = *str_it++; 18 | 19 | std::vector vec = {0,1,2,3,4,5,6,7,8,9}; 20 | 21 | //const iterator 可以改变底层的值,而 const_iterator 不能改变底层值 22 | std::vector::iterator it = vec.begin(); 23 | const std::vector::iterator cit = it; 24 | (*cit)++; 25 | std::vector::const_iterator c_it = vec.begin(); 26 | std::vector::const_iterator c_it1 = it; 27 | static_cast(it); 28 | static_cast(c_it); 29 | static_cast(c_it1); 30 | 31 | for (auto r_iter = vec.crbegin(); r_iter != vec.crend(); ++r_iter) 32 | std::cout << *r_iter << std::endl; 33 | 34 | std::string line("FIRST,MIDDLE,LAST"); 35 | auto rcomma = std::find(line.crbegin(), line.crend(), ','); 36 | std::cout << std::string(rcomma.base(), line.cend()) << std::endl; 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /code/static_class_member.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class Account { 5 | public: 6 | void calculate() 7 | { 8 | amount += amount * interestRate; 9 | } 10 | 11 | static double rate() 12 | { 13 | return interestRate; 14 | } 15 | 16 | static void rate(double); 17 | private: 18 | static constexpr int period = 20; 19 | static const double dpr; 20 | 21 | std::string owner; 22 | double amount; 23 | double daily_tbl[period]; 24 | 25 | static double interestRate; 26 | static double initRate(); 27 | }; 28 | 29 | ///////////////////////////////////////////////////////////////////// 30 | 31 | const double Account::dpr = 20.4; 32 | constexpr int Account::period; 33 | 34 | void Account::rate(double newRate) 35 | { 36 | interestRate = newRate; 37 | } 38 | 39 | double Account::interestRate = initRate(); 40 | 41 | double Account::initRate() 42 | { 43 | return 0.1; 44 | } 45 | 46 | /////////////////////////////////////////////////////////////////// 47 | 48 | class Bar { 49 | static Bar mem1; 50 | 51 | Bar *mem2; 52 | Bar &mem3; 53 | public: 54 | Bar(Bar &bar = mem1): mem3(bar) {} 55 | }; 56 | 57 | int main() 58 | { 59 | double r = Account::rate(); 60 | Account ac1; 61 | Account *ac2 = &ac1; 62 | r = ac1.rate(); 63 | r = ac2->rate(); 64 | return 0; 65 | } 66 | -------------------------------------------------------------------------------- /code/class_member_pointer.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class Screen { 5 | public: 6 | typedef std::string::size_type pos; 7 | char get_cursor() const { return contents[cursor]; } 8 | char get() const { return get(height, width); } 9 | char get(pos ht, pos wd) const { return contents[ht*10+wd]; } 10 | 11 | static const std::string Screen::* data(); 12 | public: 13 | std::string contents{"contents"}; 14 | pos cursor; 15 | pos height, width; 16 | }; 17 | 18 | const std::string Screen::* Screen::data() { 19 | return &Screen::contents; 20 | } 21 | 22 | using Action = char (Screen::*)(Screen::pos, Screen::pos) const; 23 | 24 | // action takes a reference to a Screen and a pointer to a Screen member function 25 | Screen & action(Screen &, Action = &Screen::get); 26 | 27 | int main() 28 | { 29 | const std::string Screen::*pdata = &Screen::contents; 30 | Screen myScreen, *pScreen = &myScreen; 31 | 32 | auto s = myScreen.*pdata; 33 | s = pScreen->*pdata; 34 | 35 | const std::string Screen::*pdata1 = Screen::data(); 36 | auto s1 = myScreen.*pdata1; 37 | std::cout << s1 << std::endl; 38 | 39 | // Pointers to Member Functions 40 | char (Screen::*pmf2)(Screen::pos, Screen::pos) const; 41 | pmf2 = &Screen::get; 42 | char c = (myScreen.*pmf2)(0, 0); 43 | std::cout << c << std::endl; 44 | 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /code/variadic_template.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | template 6 | void foo(const T &t, const Args &... rest) 7 | { 8 | std::cout << sizeof...(Args) << std::endl; 9 | std::cout << sizeof...(rest) << std::endl; 10 | } 11 | 12 | // This function must be declared before the variadic version of print function 13 | template 14 | std::ostream& print(std::ostream &os, const T &t) 15 | { 16 | return os << t; 17 | } 18 | 19 | template 20 | std::ostream& print(std::ostream &os, const T &t, const Args &... rest) 21 | { 22 | os << t << ", "; 23 | return print(os, rest...); 24 | } 25 | 26 | template 27 | std::string debug_rep(const T &t) 28 | { 29 | std::ostringstream ret; 30 | ret << '[' << t << ']'; 31 | return ret.str(); 32 | } 33 | 34 | template 35 | std::ostream& errorMsg(std::ostream &os, const Args &... rest) 36 | { 37 | return print(os, debug_rep(rest)...); 38 | } 39 | 40 | int main() 41 | { 42 | int i = 0; 43 | double d = 3.14; 44 | std::string s = "how now brown cow"; 45 | foo(i, s, 42, d); 46 | foo(s, 42, "hi"); 47 | foo(d, s); 48 | foo("hi"); 49 | 50 | print(std::cout, i, s, 42, d); 51 | std::cout << std::endl; 52 | 53 | errorMsg(std::cerr, i, s, 42, d, "other"); 54 | 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /code/switch.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | unsigned aCnt = 0, eCnt = 0, iCnt = 0, oCnt = 0, uCnt = 0, otherCnt = 0; 6 | char ch; 7 | while (std::cin >> ch) 8 | { 9 | switch(ch) 10 | { 11 | case 'a': 12 | ++aCnt; 13 | break; 14 | case 'e': 15 | ++eCnt; 16 | break; 17 | case 'i': 18 | ++iCnt; 19 | break; 20 | case 'o': 21 | ++oCnt; 22 | break; 23 | case 'u': 24 | ++uCnt; 25 | break; 26 | default: 27 | ++otherCnt; 28 | break; 29 | } 30 | } 31 | std::cout << "Number of vowel a: " << aCnt << std::endl; 32 | std::cout << "Number of vowel e: " << eCnt << std::endl; 33 | std::cout << "Number of vowel i: " << iCnt << std::endl; 34 | std::cout << "Number of vowel o: " << oCnt << std::endl; 35 | std::cout << "Number of vowel u: " << uCnt << std::endl; 36 | std::cout << "Number of other characters: " << otherCnt << std::endl; 37 | 38 | char c = getchar(); 39 | constexpr int ival = 42; 40 | switch(ch) { 41 | case ival: 42 | std::string file_name; 43 | int ival1 = 0; 44 | int jval; 45 | break; 46 | /* 47 | case 'b': 48 | jval = 4; 49 | break; 50 | */ //不允许跳过 label 中的变量初始化 51 | } 52 | 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /code/word_transform.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | std::map buildMap(std::ifstream &map_file) 9 | { 10 | std::map trans_map; 11 | std::string key; 12 | std::string value; 13 | while (map_file >> key && getline(map_file, value)) 14 | { 15 | if (value.size() > 1) 16 | { 17 | trans_map[key] = value.substr(1); 18 | } else 19 | throw std::runtime_error("no rule for " + key); 20 | } 21 | return trans_map; 22 | } 23 | 24 | const std::string & 25 | transform(const std::string &s, const std::map &m) 26 | { 27 | auto map_it = m.find(s); 28 | if (map_it != m.cend()) 29 | { 30 | return map_it->second; 31 | } 32 | return s; 33 | } 34 | 35 | void word_transform(std::ifstream &map_file, std::ifstream &input) 36 | { 37 | auto trans_map = buildMap(map_file); 38 | std::string text; 39 | while (getline(input, text)) { 40 | std::istringstream stream(text); 41 | std::string word; 42 | bool firstword = true; 43 | while (stream >> word) { 44 | if (firstword) 45 | firstword = false; 46 | else 47 | std::cout << " "; 48 | std::cout << transform(word, trans_map); 49 | } 50 | std::cout << '\n'; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /code/noexcept.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | // It's same as void recoup(int) noexcept(true) 7 | void recoup(int) noexcept 8 | { 9 | std::cout << "recoup" << std::endl; 10 | } 11 | 12 | void alloc(int) noexcept(false) 13 | { 14 | long long *p = new long long[10000000000000L]; 15 | delete []p; 16 | } 17 | 18 | class Base { 19 | public: 20 | virtual double f1(double) noexcept; 21 | virtual int f2() noexcept(false); 22 | virtual void f3(); 23 | }; 24 | 25 | class Derived : public Base { 26 | public: 27 | // error: Base::f1 promises not to throw 28 | //double f1(double); 29 | int f2() noexcept(false); 30 | void f3() noexcept; 31 | }; 32 | 33 | class out_of_stock : public std::runtime_error { 34 | public: 35 | explicit out_of_stock(const std::string &s): std::runtime_error(s) { } 36 | }; 37 | 38 | class isbn_mismatch : public std::logic_error { 39 | public: 40 | explicit isbn_mismatch(const std::string &s): std::logic_error(s) { } 41 | isbn_mismatch(const std::string &s, 42 | const std::string &lhs, const std::string &rhs) : 43 | std::logic_error(s), left(lhs), right(rhs) { } 44 | const std::string left, right; 45 | }; 46 | 47 | int main(int argc, char *argv[]) 48 | { 49 | void (*pf1)(int) noexcept = recoup; 50 | (*pf1)(100); 51 | void (*pf2)(int) = recoup; 52 | //pf1 = alloc; 53 | pf2 = alloc; 54 | (*pf2)(20); 55 | 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /code/ptrarray.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | std::string nums[] = {"one","two","three"}; 9 | std::string* ptr1 = &nums[0]; 10 | std::string* ptr2 = nums; 11 | std::cout << (ptr1==ptr2) << std::endl; 12 | 13 | int ia[] = {0,1,2,3,4,5,6,7,8,9}; 14 | auto ia2(ia); //int* 15 | decltype(ia) ia3 = {3,4,5,6,7,8};//int[10] 16 | ia3[4] = 100; 17 | auto e = &ia3[sizeof(ia3)/sizeof(int)]; 18 | for (auto b = ia3; b != e; ++b) 19 | { 20 | std::cout << *b << std::endl; 21 | } 22 | int arr[] = {1, 2, 3, -4, 5, 6, 7}; 23 | int *pbeg = std::begin(arr), *pend = std::end(arr); 24 | while (pbeg != pend && *pbeg >= 0) 25 | ++pbeg; 26 | std::cout << "Find a negative element: " << *pbeg << std::endl; 27 | 28 | std::ptrdiff_t n = std::end(arr) - std::begin(arr); 29 | std::cout << "element count: " << n << std::endl; 30 | 31 | //与任何普通指针一样nullptr也可以进行各种运算 32 | int *ptr = nullptr, *ptr3 = std::begin(arr); 33 | int n2 = ptr - ptr3; 34 | 35 | int i = arr[2]; 36 | int *p = &arr[2]; 37 | int j = p[1]; 38 | int k = p[-2]; 39 | std::cout << (&p[-2] == arr) << k << std::endl; 40 | 41 | int arri[] = {10,20,30,40,50,60}; 42 | int *ptri = arri; 43 | std::cout << sizeof(arri) << std::endl; 44 | std::cout << sizeof(ptri) << std::endl; 45 | int **pptr = &ptri; 46 | int (*parray)[6] = &arri; 47 | 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /code/base_function_hide.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class Base { 5 | public: 6 | virtual void f(double x) 7 | { 8 | std::cout << "Base::f(double) " << x << std::endl; 9 | } 10 | virtual void g(double x) 11 | { 12 | std::cout << "Base::g(double) " << x << std::endl; 13 | } 14 | void h(double x) 15 | { 16 | std::cout << "Base::h(double) " << x << std::endl; 17 | } 18 | //virtual void f(int x); 是编译时错误,原因是子类如果定义了 19 | //相同的静态成员函数,将不知该调用虚函数还是静态函数 20 | static void f(int x) 21 | { 22 | std::cout << "static Base::f(int) " << x << std::endl; 23 | } 24 | }; 25 | 26 | class Derived : public Base 27 | { 28 | public: 29 | virtual void f(double x) override 30 | { 31 | std::cout << "Derived::f(double) " << x << std::endl; 32 | } 33 | static void f(int x) 34 | { 35 | std::cout << "static Derived::f(int) " << x << std::endl; 36 | } 37 | virtual void g(int x) 38 | { 39 | std::cout << "Derived::g(int) " << x << std::endl; 40 | } 41 | void h(double x) 42 | { 43 | std::cout << "Derived::h(double) " << x << std::endl; 44 | } 45 | }; 46 | 47 | int 48 | main(void) 49 | { 50 | Derived d; 51 | Base *pb = &d; 52 | Derived *pd = &d; 53 | 54 | pb->f(3.14); 55 | pd->f(3.14); 56 | 57 | pb->f(3); 58 | pd->f(3); 59 | 60 | pb->g(3.14); 61 | pd->g(3.14); 62 | 63 | pb->h(3.14); 64 | pd->h(3.14); 65 | 66 | return 0; 67 | } 68 | -------------------------------------------------------------------------------- /code/use_trace_self.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "trace_self.h" 4 | 5 | TraceSelf 6 | f() 7 | { 8 | TraceSelf ret; 9 | return ret; 10 | } 11 | 12 | class HasTraceSelf_shared { 13 | public: 14 | HasTraceSelf_shared(): ts_(std::make_shared()) {} 15 | private: 16 | std::shared_ptr ts_; 17 | }; 18 | 19 | class HasTraceSelf { 20 | TraceSelf ts; 21 | }; 22 | 23 | class MoveTraceSelf { 24 | private: 25 | TraceSelf ts; 26 | public: 27 | MoveTraceSelf() = default; 28 | MoveTraceSelf(const MoveTraceSelf &) = delete; 29 | MoveTraceSelf(MoveTraceSelf &&) = default; 30 | }; 31 | 32 | int main() 33 | { 34 | f(); 35 | TraceSelf ret = f(); 36 | std::cout << "~~~~~~~~~~~~~~~~~" << std::endl; 37 | HasTraceSelf_shared hts1, hts2; 38 | hts2 = hts1; 39 | std::cout << "~~~~~~~~~~~~~~~~~~" << std::endl; 40 | HasTraceSelf_shared hts3(hts1); 41 | std::cout << "~~~~~~~~~~~~~~~~~~" << std::endl; 42 | HasTraceSelf htss1, htss2; 43 | htss2 = htss1; 44 | std::cout << "~~~~~~~~~~~~~~~~~~" << std::endl; 45 | HasTraceSelf htss3(htss1); 46 | 47 | //如果成员没有移动构造函数时,使用拷贝构造函数替代 48 | std::cout << "Synthesis move consturctor begin" << std::endl; 49 | MoveTraceSelf mts1, mts2(std::move(mts1)); 50 | std::cout << "Synthesis move consturctor end" << std::endl; 51 | 52 | //可以将 const & 绑定到任何类型 TraceSelf 上,包括右值引用 53 | TraceSelf ts1; 54 | const TraceSelf &ts2 = std::move(ts1); 55 | TraceSelf &ts3 = ts1; 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /code/template_specialization.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct Sales_data { 5 | std::string bookNo; 6 | unsigned units_sold = 0; 7 | double revenue = 0.0; 8 | }; 9 | 10 | namespace std { 11 | 12 | template <> 13 | struct hash 14 | { 15 | typedef size_t result_type; 16 | typedef Sales_data argument_type; 17 | size_t operator()(const Sales_data &s) const; 18 | }; 19 | 20 | size_t 21 | hash::operator()(const Sales_data &s) const 22 | { 23 | return hash()(s.bookNo) ^ 24 | hash()(s.units_sold) ^ 25 | hash()(s.revenue); 26 | } 27 | 28 | }; // namespace std 29 | 30 | template 31 | struct remove_reference { 32 | typedef T type; 33 | }; 34 | 35 | template 36 | struct remove_reference { 37 | typedef T type; 38 | }; 39 | 40 | template 41 | struct remove_reference { 42 | typedef T type; 43 | }; 44 | 45 | ////////////////////////////////////////////////////// 46 | 47 | template 48 | struct Foo { 49 | Foo(const T &t = T()) : mem(t) { } 50 | void Bar() { 51 | std::cout << "generic Foo::Bar()" << std::endl; 52 | std::cout << mem << std::endl; 53 | } 54 | T mem; 55 | }; 56 | 57 | template <> 58 | void Foo::Bar() 59 | { 60 | std::cout << "specialization Foo::Bar()" << std::endl; 61 | std::cout << mem << std::endl; 62 | } 63 | 64 | int main() 65 | { 66 | Foo fs; 67 | fs.Bar(); 68 | Foo fi; 69 | fi.Bar(); 70 | return 0; 71 | } 72 | -------------------------------------------------------------------------------- /code/template_member_templates.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | //Member Templates of Ordianary Classes 9 | class DebugDelete { 10 | public: 11 | DebugDelete(std::ostream &s = std::cerr) : os(s) { } 12 | 13 | template 14 | void operator()(T *p) const 15 | { 16 | os << "deleting unique_ptr" << std::endl; 17 | delete p; 18 | } 19 | private: 20 | std::ostream &os; 21 | }; 22 | 23 | //Member Templates of Class Templates 24 | template 25 | class Blob { 26 | public: 27 | template Blob(It b, It e); 28 | private: 29 | std::shared_ptr> data; 30 | }; 31 | 32 | template 33 | template 34 | Blob::Blob(It b, It e) : data(std::make_shared>(b, e)) 35 | {} 36 | 37 | template class Blob; 38 | 39 | int main() 40 | { 41 | double *p = new double(); 42 | DebugDelete d; 43 | d(p); 44 | 45 | int *ip = new int; 46 | DebugDelete()(ip); 47 | 48 | std::unique_ptr uniptr(new int, DebugDelete()); 49 | std::unique_ptr sp(new std::string, DebugDelete()); 50 | 51 | int ia[] = {0,1,2,3,4,5,6,7,8,9}; 52 | std::vector vi = {0,1,2,3,4,5,6,7,8,9}; 53 | std::list w = {"now", "is", "the", "time"}; 54 | Blob a1(std::begin(ia), std::end(ia)); 55 | Blob a2(vi.begin(), vi.end()); 56 | Blob a3(w.begin(), w.end()); 57 | 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /code/namespace_class.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace A { 4 | int i; 5 | int k; 6 | 7 | class C1 { 8 | public: 9 | C1() : i(0), j(0) { } 10 | int f1() { return k; } 11 | //int f2() { return h; } 12 | int f3(); 13 | private: 14 | int i; 15 | int j; 16 | }; 17 | 18 | int h = i; 19 | } 20 | 21 | int A::C1::f3() { return h; } 22 | 23 | namespace NS { 24 | class Quote { }; 25 | void display(const Quote &) { } 26 | } 27 | 28 | class Bulk_item : public NS::Quote { }; 29 | 30 | //////////////////////////////////////////////// 31 | 32 | namespace NS { 33 | void print(int) {} 34 | void print(double) {} 35 | } 36 | 37 | ///////////////////////////////////////////////// 38 | 39 | namespace libs_R_us { 40 | void print(int) {} 41 | void print(double) {} 42 | } 43 | 44 | void print(const std::string &) {} 45 | void print(int) {} 46 | using namespace libs_R_us; 47 | 48 | void fooBar(int ival) 49 | { 50 | print("Values: "); 51 | libs_R_us::print(ival); 52 | ::print(ival); 53 | print(1234.4567); 54 | } 55 | 56 | //////////////////////////////////////////////// 57 | 58 | namespace AW { 59 | int print(int) { return 1; } 60 | } 61 | 62 | namespace Primer { 63 | double print(double) { return 1; } 64 | } 65 | 66 | long double print(long double) { return 1; } 67 | 68 | //////////////////////////////////////////////// 69 | 70 | int main() { 71 | Bulk_item book1; 72 | 73 | //Argument-Dependent lookup 74 | display(book1); 75 | 76 | using namespace AW; 77 | using namespace Primer; 78 | } 79 | -------------------------------------------------------------------------------- /code/stringstream.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | struct PersonInfo { 8 | std::string name; 9 | std::vector phones; 10 | }; 11 | 12 | bool valid(const std::string &nums) { 13 | // All phone numbers in China are 11bit 14 | return nums.size() == 11 && (nums[0] == '1'); 15 | } 16 | 17 | std::string format(const std::string &nums) { 18 | return "+86" + nums; 19 | } 20 | 21 | int main() 22 | { 23 | std::string line, word; 24 | std::vector people; 25 | std::ifstream in("stringstream.txt"); 26 | std::ofstream out("./build/new_stringstream.txt"); 27 | while (getline(in, line)) { 28 | PersonInfo info; 29 | std::istringstream record(line); 30 | record >> info.name; 31 | while (record >> word) { 32 | info.phones.push_back(word); 33 | } 34 | people.push_back(info); 35 | } 36 | 37 | for (const auto &entry : people) { 38 | std::ostringstream formatted, badNums; 39 | for (const auto &nums : entry.phones) { 40 | if (!valid(nums)) { 41 | badNums << " " << nums; 42 | } else 43 | formatted << " " << format(nums); 44 | } 45 | if (badNums.str().empty()) { 46 | out << entry.name << " " << formatted.str() << std::endl; 47 | } else { 48 | std::cerr << "input error: " << entry.name 49 | << " invalid number(s) " << badNums.str() << std::endl; 50 | } 51 | } 52 | 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /code/func_pointer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | typedef bool (*PF)(const std::string&, const std::string&); 5 | typedef bool Func(const std::string&, const std::string&); 6 | 7 | bool lengthCompare(const std::string&, const std::string&); 8 | std::string::size_type sumLength(const std::string&, const std::string&); 9 | bool cstringCompare(const char*, const char*); 10 | 11 | typedef decltype(lengthCompare) Func2; 12 | typedef bool(*FuncP)(const std::string&, const std::string&); 13 | typedef decltype(lengthCompare) *FuncP2; 14 | 15 | void userBigger(const std::string &s1, const std::string &s2, 16 | bool pf(const std::string&, const std::string&)); 17 | 18 | void userBigger(const std::string &s1, const std::string &s2, 19 | bool (*pf)(const std::string &, const std::string &)); 20 | 21 | int main() 22 | { 23 | FuncP pf = lengthCompare; 24 | pf = &lengthCompare; 25 | bool b1 = pf("hello", "goodbye"); 26 | bool b2 = (*pf)("hello", "goodbye"); 27 | bool b3 = lengthCompare("hell", "goodbye"); 28 | std::cout << b1 << b2 << b3 << std::endl; 29 | //pf = cstringCompare; 30 | //pf = sumLength; 31 | std::string s1("hello"); 32 | std::string s2("goodbye"); 33 | userBigger(s1, s2, lengthCompare); 34 | return 0; 35 | } 36 | 37 | bool lengthCompare(const std::string& a, const std::string& b) 38 | { 39 | return a.size()>b.size(); 40 | } 41 | 42 | void userBigger(const std::string &s1, const std::string &s2, 43 | bool pf(const std::string &, const std::string &)) 44 | { 45 | bool b = pf(s1, s2); 46 | std::cout << b << std::endl; 47 | } 48 | -------------------------------------------------------------------------------- /code/TextQuery.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "TextQuery.h" 10 | 11 | TextQuery::TextQuery(std::ifstream &in) : file(new std::vector) 12 | { 13 | std::string text; 14 | while (getline(in, text)) { 15 | file->push_back(text); 16 | int n = file->size() - 1; 17 | std::istringstream line(text); 18 | std::string word; 19 | while (line >> word) { 20 | auto &lines = wm[word]; 21 | if (!lines) { 22 | lines.reset(new std::set); 23 | } 24 | lines->insert(n); 25 | } 26 | } 27 | } 28 | 29 | TextQuery::QueryResult 30 | TextQuery::query(const std::string &word) const 31 | { 32 | static std::shared_ptr> nodata(new std::set{}); 33 | auto loc = wm.find(word); 34 | if (loc == wm.end()) { 35 | return QueryResult(word, nodata, file); 36 | } else 37 | return QueryResult(word, loc->second, file); 38 | } 39 | 40 | std::string 41 | make_plural(size_t ctr, const std::string &word, const std::string &ending) 42 | { 43 | return (ctr<=1)?word:word+ending; 44 | } 45 | 46 | std::ostream& print(std::ostream &os, const TextQuery::QueryResult &qr) 47 | { 48 | os << qr.sought << " occurs " << qr.lines->size() << " " 49 | << make_plural(qr.lines->size(), "time", "s") << std::endl; 50 | for (auto num : *qr.lines) { 51 | os << "\t(line " << num + 1 << ") " 52 | << *(qr.file->begin() + num) << std::endl; 53 | } 54 | return os; 55 | } 56 | -------------------------------------------------------------------------------- /code/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY : all clean 2 | 3 | EXECUTABLES := noexcept array constexpr_class namespace_class \ 4 | multiple_inheritance \ 5 | typeinfo \ 6 | RTTI \ 7 | class_member_pointer \ 8 | function_table \ 9 | union_class \ 10 | local_class \ 11 | union \ 12 | use_sales_data \ 13 | StrVec \ 14 | StrBlob \ 15 | function_call_operator \ 16 | conversion_operator \ 17 | manipulator \ 18 | stringstream \ 19 | seq_container \ 20 | use_string \ 21 | use_container_adaptor \ 22 | overview_of_algorithms \ 23 | lambda \ 24 | bind \ 25 | iterator \ 26 | word_count \ 27 | pair \ 28 | associative_container \ 29 | rvalue_reference \ 30 | explict_cast \ 31 | new_align \ 32 | tuple \ 33 | bitset \ 34 | regex \ 35 | random \ 36 | io_revisit \ 37 | 38 | OBJS := ShowBackStageCls 39 | 40 | BUILD_PATH = build 41 | 42 | all : \ 43 | $(foreach v, $(EXECUTABLES), $(BUILD_PATH)/$(v).exe) \ 44 | $(foreach v, $(OBJS), $(BUILD_PATH)/$(v).o) \ 45 | $(BUILD_PATH)/use_ShowBackStageCls.exe 46 | 47 | CXX := g++ 48 | CXXFLAGS += -std=c++11 -Wall 49 | 50 | $(BUILD_PATH) : 51 | @mkdir $(BUILD_PATH) 52 | 53 | define COMPILE_template 54 | $$(BUILD_PATH)/$(1).exe : $(1).cc | $$(BUILD_PATH) 55 | $$(CXX) $$(CXXFLAGS) $$^ -o $$@ 56 | endef 57 | 58 | $(foreach v, $(EXECUTABLES), $(eval $(call COMPILE_template,$(v)))) 59 | 60 | define COMPILE_obj_template 61 | $$(BUILD_PATH)/$(1).o : $(1).cc | $$(BUILD_PATH) 62 | $$(CXX) $$(CXXFLAGS) -c $$^ -o $$(@) 63 | endef 64 | 65 | $(foreach v, $(OBJS), $(eval $(call COMPILE_obj_template,$(v)))) 66 | 67 | $(BUILD_PATH)/use_ShowBackStageCls.exe : use_ShowBackStageCls.cc $(BUILD_PATH)/ShowBackStageCls.o 68 | $(CXX) $(CXXFLAGS) $(^) -o $(@) 69 | 70 | clean: 71 | rm -rf $(BUILD_PATH) 72 | -------------------------------------------------------------------------------- /code/multiple_inheritance.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | class ZooAnimal {}; 6 | class Endangered { 7 | public: 8 | static constexpr int critical = 1; 9 | 10 | Endangered(int degree): degree(degree) {} 11 | private: 12 | int degree; 13 | }; 14 | 15 | constexpr int Endangered::critical; 16 | 17 | class Bear : public ZooAnimal { 18 | public: 19 | Bear(const std::string &name, bool onExhibit, const std::string &family) : 20 | name(name), onExhibit(onExhibit), family(family) 21 | {} 22 | Bear(): name("UNKNOWN"), onExhibit(false), family("Bear") {} 23 | private: 24 | std::string name; 25 | bool onExhibit; 26 | std::string family; 27 | }; 28 | 29 | class Panda : public Bear, public Endangered { 30 | public: 31 | Panda(const std::string &name, bool onExhibit); 32 | Panda(); 33 | }; 34 | 35 | Panda::Panda(const std::string &name, bool onExhibit) : 36 | Bear(name, onExhibit, "Panda"), 37 | Endangered(Endangered::critical) { } 38 | 39 | Panda::Panda() : Endangered(Endangered::critical) {} 40 | 41 | //////////////////////////////////////////////////////////////// 42 | 43 | struct Base1 { 44 | Base1() = default; 45 | Base1(const std::string &) {} 46 | Base1(std::shared_ptr) {} 47 | }; 48 | 49 | struct Base2 { 50 | Base2() = default; 51 | Base2(const std::string &) {} 52 | Base2(int) {} 53 | }; 54 | 55 | struct D1 : public Base1, public Base2 { 56 | // Inherit constructors from Base1 and Base2, 57 | // But there are some consturctors which is ambiguous, 58 | // We must define our own. 59 | using Base1::Base1; 60 | using Base2::Base2; 61 | D1(const std::string &s) : Base1(s), Base2(s) { } 62 | // needed once D2 defines its own constructors 63 | D1() = default; 64 | }; 65 | 66 | int main() { 67 | std::string str("D1"); 68 | D1 d(str); 69 | } 70 | -------------------------------------------------------------------------------- /code/bitset.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | int main() 8 | { 9 | std::bitset<32> bitvec(1U); 10 | std::bitset<13> bitvec1(0xbeef); 11 | std::bitset<20> bitvec2(0xbeef); 12 | std::bitset<256> bitvec3(~0ULL); 13 | std::bitset<32> bitvec4("1100"); 14 | 15 | std::string str("1111111000000011001101"); 16 | std::bitset<32> bitvec5(str, 5, 4); 17 | std::bitset<32> bitvec6(str, str.size()-4); 18 | 19 | std::cout << "bitvec1: " << bitvec1 << std::endl; 20 | std::cout << "bitvec2: " << bitvec2 << std::endl; 21 | 22 | bool is_set = bitvec.any(); 23 | bool is_not_set = bitvec.none(); 24 | bool all_set = bitvec.all(); 25 | size_t onBits = bitvec.count(); 26 | size_t sz = bitvec.size(); 27 | 28 | bitvec.flip(); 29 | bitvec.reset(); 30 | bitvec.set(); 31 | 32 | printf("%d %d %u %lu %lu\n", is_set, is_not_set, all_set, onBits, sz); 33 | 34 | //The nonconst version returns a special type defined by bitset 35 | //that lets us manipulate the bit value at the given index position: 36 | bitvec[0] = 0; 37 | bitvec[31] = bitvec[0]; 38 | bitvec[0].flip(); 39 | ~bitvec[0]; 40 | bool b = bitvec[0]; 41 | 42 | //to_ulong and to_ullong can be used only if the size of the 43 | //bitset is less than or equal to the corresponding size. 44 | unsigned long ulong = bitvec3.to_ulong(); 45 | std::cout << "ulong = " << ulong << std::endl; 46 | std::cout << "ULLONG_MAX = " << ULLONG_MAX << std::endl; 47 | std::cout << "ULONG_MAX = " << ULONG_MAX << std::endl; 48 | std::cout << "size of ulong: " << sizeof(unsigned long) << std::endl; 49 | std::cout << "size of ulong: " << sizeof(unsigned long long) << std::endl; 50 | 51 | //bitvec3.set(65, 1); //cause overflow_error 52 | unsigned long long ullong = bitvec3.to_ullong(); 53 | std::cout << "ullong = " << ullong << std::endl; 54 | 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /docs/CH17_Specialized_Library_Facilities.md: -------------------------------------------------------------------------------- 1 | ## 17.1 tuple 类型 2 | 3 | ### 17.1.1 定义和初始化 tuple 4 | 5 | **访问 tuple 的成员** 6 | 7 | **关系和相等操作符** 8 | 9 | ### 17.1.2 使用 tuple 以返回多个值 10 | 11 | **返回 tuple 的函数** 12 | 13 | **使用函数返回的 tuple** 14 | 15 | ### 17.2 bitset 类型 16 | 17 | ### 17.2.1 定义和初始化 bitset 18 | 19 | **用 unsigned 初始化 bitset** 20 | 21 | **用 string 初始化 bitset** 22 | 23 | ### 17.2.2 bitset 上的操作 24 | 25 | **从 bitset 中获取值** 26 | 27 | **bitset 的 IO 操作符** 28 | 29 | **使用 bitset** 30 | 31 | ## 17.3 正则表达式 32 | 33 | ### 17.3.1 使用正则表达式库 34 | 35 | **为 regex 对象指定选项** 36 | 37 | **指定或使用正则表达式可能产生的错误** 38 | 39 | **正则表达式类和输入序列类型** 40 | 41 | ### 17.3.2 匹配和正则迭代器类型 42 | 43 | **使用 `sregex_iterator`** 44 | 45 | **使用匹配数据** 46 | 47 | ### 17.3.3 使用子表达式 48 | 49 | **子表达式用于数据验证** 50 | 51 | **使用子匹配操作** 52 | 53 | ### 17.3.4 使用 `regex_replace` 54 | 55 | **只替换输入序列的一部分** 56 | 57 | **控制匹配和格式化的标志** 58 | 59 | **使用格式化标志** 60 | 61 | ## 随机数 62 | 63 | ### 17.4.1 随机数引擎和分布 64 | 65 | **分布类型和引擎** 66 | 67 | **比较随机引擎和 rand 函数** 68 | 69 | **引擎生成数字序列** 70 | 71 | **给生成器设定种子** 72 | 73 | ### 17.4.2 其它类型的分布 74 | 75 | **生成随机实数** 76 | 77 | **使用分布的默认结果类型** 78 | 79 | **生成不是统一分布(Not Uniformly Distributed)的数字** 80 | 81 | **`bernoulli_distribution`类** 82 | 83 | ## 17.5 再谈 IO 库 84 | 85 | ### 17.5.1 格式化输入和输出 86 | 87 | **许多操纵子(Manipulators)改变格式状态** 88 | 89 | **控制布尔值的格式** 90 | 91 | **设置整数值的基数** 92 | 93 | **在输出中指示基数** 94 | 95 | **控制浮点数的格式** 96 | 97 | **指定打印的精度** 98 | 99 | **指定浮点数的记号法** 100 | 101 | **打印十进制的小数点** 102 | 103 | **填充输出** 104 | 105 | **控制输入格式** 106 | 107 | ### 17.5.2 未格式化的输入、输出操作 108 | 109 | **单字节操作** 110 | 111 | **重新放回输入流** 112 | 113 | **从输入操作中返回的 int 值** 114 | 115 | **多字节操作** 116 | 117 | **决定要读取多少个字符** 118 | 119 | ### 17.5.3 随机访问流 120 | 121 | **警告:底层例程是容易出错的** 122 | 123 | **seek 和 tell 函数** 124 | 125 | **只有一个标记(Marker)** 126 | 127 | **重新定位标记** 128 | 129 | **访问标记** 130 | 131 | **读写同一个文件** -------------------------------------------------------------------------------- /code/Quote.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class Quote { 5 | public: 6 | Quote() = default; 7 | Quote(const std::string &book, double sales_price): 8 | bookNo(book), price(sales_price) { } 9 | std::string isbn() const { return bookNo; } 10 | virtual double net_price(std::size_t n) const { return n * price; } 11 | virtual ~Quote() = default; 12 | private: 13 | std::string bookNo; 14 | protected: 15 | double price = 0.0; 16 | }; 17 | 18 | class Bulk_quote : public Quote { 19 | public: 20 | Bulk_quote() = default; 21 | Bulk_quote(const std::string &book, double p, std::size_t qty, double disc) 22 | : Quote(book, p), min_qty(qty), discount(disc) { } 23 | double net_price(std::size_t) const override; 24 | private: 25 | std::size_t min_qty = 0; 26 | double discount = 0.0; 27 | }; 28 | 29 | double 30 | Bulk_quote::net_price(std::size_t cnt) const 31 | { 32 | if (cnt >= min_qty) 33 | return cnt * (1 - discount) * price; 34 | else 35 | return Quote::net_price(cnt); 36 | } 37 | 38 | double 39 | print_total(std::ostream &os, const Quote &item, std::size_t n) 40 | { 41 | double ret = item.net_price(n); 42 | os << "ISBN: " << item.isbn() 43 | << " # sold: " << n << " total due: " << ret << std::endl; 44 | return ret; 45 | } 46 | 47 | int 48 | main() 49 | { 50 | Quote basic("XY-98763454234", 20.05); 51 | Bulk_quote bulk("XY-83243234123", 45.98, 30, 0.2); 52 | print_total(std::cout, basic, 20); 53 | print_total(std::cout, bulk, 39); 54 | 55 | Quote item; 56 | Quote *p = &item; 57 | p = &bulk; 58 | Quote &r = bulk; 59 | 60 | //Bulk_quote *bulkP = &basic; 61 | //Bulk_quote &bulkRef = basic; 62 | 63 | //Quote *itemP = &bulk; 64 | //Bulk_quote *bulkP = itemP; 65 | 66 | Quote item1(bulk); 67 | item = bulk; 68 | 69 | Quote *baseP = &bulk; 70 | double undiscounted = baseP->Quote::net_price(42); 71 | return 0; 72 | } 73 | -------------------------------------------------------------------------------- /code/new_delete.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "trace_self.h" 6 | 7 | int main() 8 | { 9 | int *pi = new int; //unnamed, uninitialized int 10 | std::string *ps = new std::string; //default initialized, empty string 11 | 12 | int *pi2 = new int(1024); //int object has value 1024 13 | std::string *ps2 = new std::string(10, '9'); //*ps is "9999999999" 14 | std::vector *pv = new std::vector{0,1,2,3,4,5,6,7,8,9}; 15 | std::cout << *ps2 << std::endl; 16 | 17 | std::string *ps3 = new std::string; //default initialized 18 | std::string *ps4 = new std::string(); //value initialized 19 | std::string *ps5 = new std::string{}; //value initialized, since c++11 20 | int *pi3 = new int; //*pi3 is undefined 21 | int *pi4 = new int(); //value initialized, *pi4 = 0 22 | int *pi5 = new int{}; //value initialized, since c++11 23 | 24 | auto pauto = new auto(*pi2); 25 | std::cout << *pauto << std::endl; 26 | 27 | const int *pci = new const int(1024); 28 | //next line: undefined, using to initialize a pointer to const int 29 | const int *pci2 = new int; 30 | const std::string *pcs = new const std::string; 31 | std::cout << "*pci: " << *pci << " *pci2: " << *pci2 << std::endl; 32 | 33 | int *p1 = new int; 34 | int *p2 = new (std::nothrow) int; 35 | 36 | std::cout << "Before delete ~~~" << std::endl; 37 | TraceSelf *pts = new TraceSelf; 38 | delete pts; 39 | std::cout << "After delete ~~~~" << std::endl; 40 | 41 | int i, *pi6 = &i, *pi7 = nullptr; 42 | double *pd = new double(33), *pd2 = pd; 43 | // delete i; //error!! i is not a pointer 44 | delete pi6; //error, but compile can't tell, pi6 points to local object 45 | delete pd; 46 | delete pd2; //error, the memory pointed to by pd2 was already freed 47 | delete pi7; //delete a null pointer is ok 48 | 49 | const int *pci3 = new const int(1024); 50 | delete pci3; 51 | 52 | return 0; 53 | } 54 | -------------------------------------------------------------------------------- /code/protected_access.cc: -------------------------------------------------------------------------------- 1 | class Base { 2 | friend class Pal; 3 | public: 4 | void pub_mem(); 5 | protected: 6 | int prot_mem; 7 | private: 8 | char priv_mem; 9 | }; 10 | 11 | class Sneaky : public Base { 12 | friend void clobber(Sneaky &); 13 | friend void clobber(Base &); 14 | private: 15 | int j; 16 | }; 17 | 18 | void 19 | clobber(Sneaky &s) 20 | { 21 | s.j = s.prot_mem; 22 | } 23 | 24 | void 25 | clobber(Base &b) 26 | { 27 | //非派生类不能访问其受保护字段 28 | //b.prot_mem = 0; 29 | } 30 | 31 | ////////////////////////////////////////////////////////////////// 32 | struct Pub_Derv : public Base { 33 | int f() { return prot_mem; } 34 | //派生类不能访问私有成员 35 | //char g() { return priv_mem; } 36 | }; 37 | 38 | struct Priv_Derv : private Base { 39 | int f1() const { return prot_mem; } 40 | }; 41 | 42 | struct Prot_Derv : protected Base { 43 | int f() { return prot_mem; } 44 | }; 45 | 46 | struct Derived_from_Public : public Pub_Derv { 47 | int use_base() { 48 | pub_mem(); 49 | return prot_mem; 50 | } 51 | }; 52 | 53 | struct Derived_from_Private : public Priv_Derv { 54 | int use_base() { 55 | //pub_mem(); 56 | //错误:Base::prot_mem 是 Priv_Derv 的私有成员 57 | //return prot_mem; 58 | return 0; 59 | } 60 | }; 61 | 62 | struct Derived_from_Protected : public Prot_Derv { 63 | int use_base() { 64 | pub_mem(); 65 | return prot_mem; 66 | } 67 | }; 68 | 69 | ////////////////////////////////////////////////////////////////////////// 70 | 71 | class Pal { 72 | public: 73 | int f(Base b) { return b.prot_mem; } 74 | //int f2(Sneaky s) { return s.j; } 75 | int f3(Sneaky s) { return s.priv_mem; } 76 | }; 77 | 78 | class D2 : public Pal { 79 | public: 80 | int mem(Base b) { 81 | //return b.prot_mem; 82 | return 0; 83 | } 84 | }; 85 | 86 | int 87 | main() 88 | { 89 | Pub_Derv d1; 90 | Priv_Derv d2; 91 | Prot_Derv d3; 92 | d1.pub_mem(); 93 | //私有派生的用户代码不能访问子类的公有成员 94 | //d2.pub_mem(); 95 | //d3.pub_mem(); 96 | return 0; 97 | } 98 | -------------------------------------------------------------------------------- /code/newscreen_window_mgr.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | class Screen; 6 | 7 | class Windows_mgr { 8 | public: 9 | using ScreenIndex = std::vector::size_type; 10 | public: 11 | Windows_mgr(); 12 | void clear(ScreenIndex); 13 | ScreenIndex addScreen(const Screen&); 14 | private: 15 | std::vector screens; 16 | }; 17 | 18 | int height; 19 | 20 | class Screen { 21 | friend void Windows_mgr::clear(ScreenIndex); 22 | public: 23 | typedef std::string::size_type pos; 24 | // alternative way to declare a type member using a type alias 25 | //using pos = std::string::size_type; 26 | 27 | Screen() = default; 28 | 29 | Screen(pos ht, pos wd, char c) : 30 | height(ht), 31 | width(wd), 32 | contents(ht*wd, c) 33 | {} 34 | 35 | char get() const 36 | { 37 | return contents[cursor]; 38 | } 39 | 40 | inline char get(pos ht, pos wd) const; 41 | 42 | Screen &move(pos r, pos c); 43 | 44 | void dummy_func(pos height) 45 | { 46 | cursor = width * height; 47 | cursor = width * this->height; 48 | cursor = width * Screen::height; 49 | cursor = width * ::height; 50 | } 51 | private: 52 | pos cursor = 0; 53 | pos height = 0, width = 0; 54 | std::string contents; 55 | }; 56 | 57 | /////////////////////////////////////////////////////////////////// 58 | 59 | Windows_mgr::Windows_mgr() : 60 | screens{Screen(24, 80, ' ')} 61 | {} 62 | 63 | void Windows_mgr::clear(ScreenIndex i) 64 | { 65 | Screen &s = screens[i]; 66 | s.contents = std::string(s.height*s.width, ' '); 67 | } 68 | 69 | Windows_mgr::ScreenIndex 70 | Windows_mgr::addScreen(const Screen &s) 71 | { 72 | screens.push_back(s); 73 | return screens.size() - 1; 74 | } 75 | 76 | ////////////////////////////////////////////////////////////////// 77 | 78 | int main() 79 | { 80 | Screen::pos ht = 24, wd = 80; 81 | Screen scr(ht, wd, ' '); 82 | Screen *p = &scr; 83 | char c = scr.get(); 84 | c = p->get(); 85 | return 0; 86 | } 87 | -------------------------------------------------------------------------------- /code/use_has_ptr.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | //value-like 6 | class HasPtr { 7 | friend void swap(HasPtr &lhs, HasPtr &rhs); 8 | public: 9 | HasPtr(const std::string &s = std::string()): 10 | ps(new std::string(s)), i(0) { } 11 | 12 | HasPtr(const HasPtr &orig); 13 | 14 | //move constructor 15 | HasPtr(HasPtr &&p) noexcept : ps(p.ps), i(p.i) 16 | { p.ps = nullptr; } 17 | 18 | ~HasPtr(); 19 | 20 | //HasPtr& operator=(const HasPtr &rhs); 21 | 22 | //copy-and-swap assignment operator 23 | HasPtr& operator=(HasPtr rhs) 24 | { 25 | swap(*this, rhs); 26 | return *this; 27 | } 28 | private: 29 | std::string *ps; 30 | int i; 31 | }; 32 | 33 | HasPtr::~HasPtr() 34 | { 35 | std::cout << "destructor" << std::endl; 36 | delete ps; 37 | } 38 | 39 | /* 40 | HasPtr& HasPtr::operator=(const HasPtr &rhs) 41 | { 42 | if (this == &rhs) 43 | return *this; 44 | 45 | //应当先执行拷贝,然后再执行清理原来的状态 46 | auto newp = new std::string(*rhs.ps); 47 | 48 | delete ps; 49 | ps = newp; 50 | i = rhs.i; 51 | 52 | return *this; 53 | } 54 | */ 55 | 56 | HasPtr::HasPtr(const HasPtr &orig): 57 | //如果注释掉下面这句将导致一个内存释放多次,这是错误!! 58 | //以下是运行时错误: 59 | //malloc: *** error for object 0x7ffee5775548: 60 | //pointer being freed was not allocated 61 | ps(new std::string(*orig.ps)), 62 | i(orig.i) 63 | { 64 | std::cout << "copy constructor" << std::endl; 65 | } 66 | 67 | HasPtr f(HasPtr hp) 68 | { 69 | HasPtr ret = hp; 70 | return ret; 71 | } 72 | 73 | inline void swap(HasPtr &lhs, HasPtr &rhs) 74 | { 75 | using std::swap; 76 | swap(lhs.ps, rhs.ps); 77 | swap(lhs.i, rhs.i); 78 | } 79 | 80 | int main() 81 | { 82 | HasPtr p("some values"); 83 | HasPtr q = p; 84 | f(p); 85 | 86 | HasPtr hp1 = std::string("swap1"); 87 | HasPtr hp2 = std::string("swap2"); 88 | swap(hp1, hp2); 89 | 90 | HasPtr hp3 = std::string("hp3"); 91 | HasPtr hp4 = std::string("hp4"); 92 | hp3 = hp4; 93 | hp4 = std::string("hp4"); 94 | 95 | return 0; 96 | } 97 | -------------------------------------------------------------------------------- /docs/CH00_Preface.md: -------------------------------------------------------------------------------- 1 | # 开始 2 | 3 | 万事开头难,开始意味着做出改变,而接下来的任何动作都是延续之前的行为,因为人的强大适应能力而一旦适应了想要再改变就会引起大脑的强烈反应。这有利于人适应环境,也会导致人的思维固化,所以偶尔的外来刺激会导致大脑获得新的认知。这是创造的必要条件。 4 | 5 | 接下来的几个月时间,我将会把主要精力放在为 《C++ Primer 5th》 这本书的笔记上。C++ 在我多年以来断断续续学了好几遍,之前用《C++ 编程思想》也学过,但那本书过于陈旧了,用《C++ Primer 4th》也学过一段时间,由于书本过于沉溺细节,导致最终没法坚持下来。第五版我去年已经看过一遍了,对于里边的内容也有一个大概的印象,我的一个感受就是第五版的内容安排变好了,而且很多过于细节化的东西被隐藏了。这是非常好的,对于初学者来说更重要的是看到语言的全貌而不是抠细节,我们得知道语言的边界从而为要解决的问题提供良好定义的方案。 6 | 7 | 我之前得到一些启发,说学习 C 不应该一开始就将 printf 的各种参数细节,这太过于机械记忆。只要用到的时候去查阅对应的文档即可。学太多这种东西,反而妨碍了了解语言的能力和限制,以及怎样设计具有良好结构的程序。所以,在所有这些笔记中如果是过于细节化的东西,我会省略掉,当需要时阅读原文即可。我希望笔记达到的功能是提醒所有想用好 C++ 语言的程序员这门语言的核心是什么。细枝末节将会被忽略。 8 | 9 | 10 | 好,以下是 《C++ Primer 5th》的笔记正文,供各位慢慢阅读。 11 | 12 | # 前言 13 | 14 | C++ 语言经过几十年的发展,已经从当初仅仅关注机器效率渐渐开始更加关注开发效率。这很大程度是由于别的语言的冲击,Python 、Javascript 这些语言的开发效率相对来说要高不少,渐渐 C++ 也往这方面考虑。由于 C++ 即想保持机器效率,又想最大化开发效率,导致现在语言特性繁多而且还在不断增加,这是不得已的妥协。 15 | 16 | C++11 是目前最广为接受的现代 C++ 标准,近些年还发展出了 C++14 和 C++17 标准,都是在 C++11 上进行小幅扩展的。这本书所讲的内容都是关于 C++11 的。 17 | 18 | C++11 具有语言更加统一,标准库更易用更安全并且更高效,动手写自己的库也更加容易的特点。比如 auto 关键字的广泛使用导致程序员可以忽略类型细节,将精力放在解决问题上而不是语言细节上。而智能指针和移动容器(move-enabled containers)使得程序员可以更少关注资源管理(resource management)方面的细节,从而可以更加安全高效的写复杂的库。 19 | 20 | 本书会用 `C++11` 标记所有 C++11 添加的新特性,为的是在需要区分这些特性时更容易找到。尽管新标准增添了许多特性,C++ 语言的核心并没有改变,并构成了本书的主要内容。 21 | 22 | # 为什么是这一本? 23 | 24 | 现代 C++ 语言由以下三部分组成: 25 | 26 | 1. 从 C 语言继承而来的低层(low-level)语言细节; 27 | 2. 允许定义自己的类型的 OOP 编程方式,从而构建大的程序和系统; 28 | 3. 丰富的标准库; 29 | 30 | 很多别的书一开始就将很多关于 C 语言的细节,让读者学一堆动态内存管理和指针的内容,导致读者深陷低层语言的细节从而导致在挫败中放弃。这不是正确的学习 C++ 的方式,正确的方式是一开始就利用 C++ 语言丰富的标准库,而忽略掉低层语言细节,这样写出来的程序更容易写、更容易懂、更健壮。本书将帮助读者从一开始就养成正确的习惯。本书将强调惯用的技巧,提醒读者避免 C++ 中常见的坑,本书也将解释规则后面的原因,知道了为什么是这样读者将更快掌握语言的精髓。 31 | 32 | C++ 是一门很大的语言,包含了为各种问题定制的方案。其中一些仅适用于大的项目,而小项目用不上。所以并不是所有程序员需要了解每个特性的所有细节。每个人都需要了解语言的核心部分,而一些高级以及很偏门(special-purpose)的主题可以快速浏览,并在真正需要时才用心研究这些特性。C++ 语言中还有一些概念对于理解整个语言有至关重要的意义,这些部分值的好好理解。 33 | 34 | 本书的第一、二部分讲的是语言的基础和库的使用,这两个部分是语言的核心,知道了这些部分就可以阅读和写出很多重要的软件。绝大部分程序要都需要这两部分的所有细节。C++ 中的库虽然实现复杂,但全部都是以 C++ 语言本身写就的,在体验库的强大的同时,也了解到语言的威力。学习 C++ 更为重要一点并不在于沉溺于 C 语言的细节,而在于其强大的抽象能力。想想 C++ 的库比 C 库大多少就知道了,C++ 是一门比 C 抽象程度更高的语言。 35 | 36 | 本书的第三部分教大家怎么写自己的类,其中涉及到拷贝控制(copy control),以及其它使得自定义类像内置类型一样易用的特性。第三部分也会将关于泛型编程(generic programming)的知识。第四部分则将在大型程序中用到的技术。 37 | 38 | 最后:学习任何语言都需要多写代码,用它去解决实际的问题,才能做到有效学习。 -------------------------------------------------------------------------------- /code/multiarray.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using int_array = int[4]; 5 | 6 | int main() 7 | { 8 | int arr[10][20][30] = {0}; 9 | int *ptrarr = **arr; 10 | int *endptr = **std::end(arr); 11 | int ct = 0; 12 | for (;ptrarr < endptr; ptrarr++) 13 | { 14 | ct++; 15 | } 16 | std::cout << ct << std::endl; 17 | 18 | int ia[3][4] = { 19 | 0,1,2,3,4,5,6,7, 20 | {8,9,10,11}, 21 | }; 22 | for (auto p=*std::begin(ia), q=*std::end(ia); p 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | void fcn1() 9 | { 10 | size_t v1 = 42; 11 | auto f = [v1]{ return v1; }; 12 | v1 = 0; 13 | auto j = f(); 14 | std::cout << "v1: " << v1 << " j: " << j << std::endl; 15 | } 16 | 17 | void fcn2() 18 | { 19 | size_t v1 = 42; 20 | auto f2 = [&v1] { return v1; }; 21 | v1 = 0; 22 | auto j = f2(); 23 | std::cout << "v1: " << v1 << " j: " << j << std::endl; 24 | } 25 | 26 | void fcn4() 27 | { 28 | size_t v1 = 42; 29 | // v1 is a reference to a non const variable, 30 | // we can change that variable through the reference inside f2 31 | auto f2 = [&v1] { return ++v1; }; 32 | v1 = 0; 33 | auto j = f2(); 34 | } 35 | 36 | void biggies( 37 | std::vector &words, 38 | std::vector::size_type sz, 39 | std::ostream &os = std::cout, 40 | char c = ' ') 41 | { 42 | std::for_each(words.begin(), words.end(), 43 | [&os, c](const std::string &s) { os << s << c; }); 44 | // [&, c] (const std::string &s) { os << s << c; } 45 | // [=, &os] (const std::string &s) { os << s << c; } 46 | } 47 | 48 | void fcn3() 49 | { 50 | size_t v1 = 42; 51 | auto f= [v1]() mutable { return ++v1; }; 52 | v1 = 0; 53 | auto j = f(); 54 | std::cout << "v1: " << v1 << " j: " << j << std::endl; 55 | } 56 | 57 | int main() 58 | { 59 | auto f = []{ return 42; }; 60 | std::cout << f() << std::endl; 61 | fcn1(); 62 | fcn2(); 63 | fcn3(); 64 | std::vector words{"the","quick","red","fox","jumps","over","the","slow","red","turtle"}; 65 | int sz = 4; 66 | biggies(words, sz); 67 | auto wc = std::find_if(words.begin(), words.end(), 68 | [=](const std::string &s) { return s.size() >= sz; }); 69 | int ia[] = {27, 210, 12, 47, 109, 83}; 70 | std::transform(std::begin(ia), std::end(ia), std::begin(ia), 71 | [](int i) { return i < 0 ? -i : i; }); 72 | 73 | std::transform(std::begin(ia), std::end(ia), std::begin(ia), 74 | [](int i) -> int { 75 | if (i < 0) return -i; 76 | else return i; 77 | }); 78 | return 0; 79 | } 80 | -------------------------------------------------------------------------------- /code/word_count.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | std::map word_count; 9 | std::set exclude = { 10 | "The", 11 | "But", 12 | "And", 13 | "Or", 14 | "An", 15 | "A", 16 | "the", 17 | "but", 18 | "and", 19 | "or", 20 | "an", 21 | "a" 22 | }; 23 | std::string word; 24 | while (std::cin >> word) { 25 | if (exclude.find(word) == exclude.end()) { 26 | // (1) equals 27 | ++word_count[word]; 28 | // (2) equals 29 | auto ret = word_count.insert({word, 1}); 30 | if (!ret.second) 31 | ++ret.first->second; 32 | } 33 | } 34 | for (const auto &w : word_count) 35 | std::cout << w.first << " occurs " << w.second 36 | << ((w.second > 1) ? " times" : " time") << std::endl; 37 | 38 | if (word_count.find("foobar") == word_count.end()) 39 | std::cout << "foobar is not in the map" << std::endl; 40 | 41 | std::cout << "======================\n" << std::endl; 42 | auto map_it1 = word_count.cbegin(); 43 | while (map_it1 != word_count.cend()) { 44 | std::cout << map_it1->first << " occurs " 45 | << map_it1->second << " times " << std::endl; 46 | ++map_it1; 47 | } 48 | 49 | std::map authors = { 50 | { "Joyce" , "James" } , 51 | { "Austen" , "Jane" } , 52 | { "Dickens" , "Charles" } 53 | }; 54 | 55 | // compare multiset and set 56 | std::vector ivec; 57 | for (std::vector::size_type i = 0; i != 10; ++i) { 58 | ivec.push_back(i); 59 | ivec.push_back(i); 60 | } 61 | std::set iset(ivec.cbegin(), ivec.cend()); 62 | std::multiset miset(ivec.cbegin(), ivec.cend()); 63 | std::cout << ivec.size() << std::endl; 64 | std::cout << iset.size() << std::endl; 65 | std::cout << miset.size() << std::endl; 66 | 67 | auto map_it = word_count.begin(); 68 | std::cout << map_it->first; 69 | std::cout << " " << map_it->second; 70 | //map_it->first = "new key"; 71 | ++map_it->second; 72 | 73 | return 0; 74 | } 75 | -------------------------------------------------------------------------------- /code/use_shared_ptr.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "trace_self.h" 8 | 9 | std::shared_ptr factory(int arg) 10 | { 11 | (void)arg; 12 | return std::make_shared(); 13 | } 14 | 15 | void use_factory(int arg) 16 | { 17 | auto p = factory(arg); 18 | } 19 | 20 | decltype(factory(100)) use_factory2(int arg) 21 | { 22 | auto p = factory(arg); 23 | return p; 24 | } 25 | 26 | std::shared_ptr clone(int p) 27 | { 28 | return std::shared_ptr(new int(p)); 29 | } 30 | 31 | int main() 32 | { 33 | std::shared_ptr p1; 34 | std::shared_ptr> p2; 35 | 36 | if (p1 && p1->empty()) 37 | *p1 = "hi"; 38 | else 39 | std::cout << "p1 is nullptr or not empty" << std::endl; 40 | 41 | std::shared_ptr p3 = std::make_shared(42); 42 | std::shared_ptr p4 = std::make_shared(10, '9'); 43 | std::shared_ptr p5 = std::make_shared(); //不提供参数,int 类型值将被值初始化 44 | 45 | std::cout << *p5 << std::endl; 46 | 47 | auto p6 = std::make_shared>(); 48 | 49 | ///////////////////////////// 50 | // object to which p points has one user 51 | auto p = std::make_shared(); 52 | //object to wich p and q point has two users 53 | auto q(p); 54 | auto r = std::make_shared(); 55 | std::cout << "~~~~Before assigned" << std::endl; 56 | r = q; 57 | std::cout << "~~~~After assigned" << std::endl; 58 | 59 | std::cout << "~~~~Before use_factory" << std::endl; 60 | use_factory(100); 61 | std::cout << "~~~~After use_factory" << std::endl; 62 | 63 | std::cout << "~~~~Before use_factory2" << std::endl; 64 | auto p7 = use_factory2(100); 65 | std::cout << "~~~~After use_factory2" << std::endl; 66 | 67 | std::shared_ptr p8 = static_cast(new int(1024)); 68 | std::shared_ptr p9(new int(1024)); 69 | auto p10(p9); 70 | 71 | if (!p10.unique()) 72 | { 73 | p10.reset(new int(100)); 74 | } 75 | *p10 += 20; 76 | std::cout << "*p9: " << *p9 << " *p10: " << *p10 << std::endl; 77 | 78 | int *pi = new int(2048); 79 | p9.reset(pi); 80 | //p9 = pi; //不能直接将指针赋值给 shared_ptr 81 | 82 | return 0; 83 | } 84 | -------------------------------------------------------------------------------- /toc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | from __future__ import print_function 5 | import os 6 | import re 7 | 8 | headPattern = re.compile(r"\s*((#+)\s*(.*))") 9 | blockPattern = re.compile(r"\s*(````)") 10 | 11 | def listfiles(dir): 12 | files = os.listdir(dir) 13 | files.sort() 14 | for i in xrange(len(files)): 15 | files[i] = dir + "/" + files[i] 16 | return files 17 | 18 | def parsefile(f): 19 | ret = {"file":f,"heads":[]} 20 | codeblock = False 21 | for line in file(f): 22 | if codeblock: 23 | m = False 24 | if blockPattern.match(line): 25 | codeblock = False 26 | else: 27 | m = headPattern.match(line) 28 | if blockPattern.match(line): 29 | codeblock = True 30 | if m: 31 | # 移除 Windows 的换行符 \r 32 | hstr = m.group(3).replace('\r', '') 33 | ret['heads'].append((len(m.group(2)), hstr)) 34 | return ret 35 | 36 | def tomarkdown(fstruct): 37 | str_lst = [] 38 | pattern = re.compile(ur"""[!\"#$%&'()*+,./:;<=>?@[\]^`{|}~]""") 39 | str_lst.append("\n## [{}]({})".format(fstruct['file'], fstruct['file'])) 40 | for h in fstruct['heads']: 41 | hstr = h[1] 42 | hstr = pattern.sub('', hstr) 43 | hstr = hstr.replace('(', '') 44 | hstr = hstr.replace(')', '') 45 | hstr = hstr.replace(':', '') 46 | hstr = hstr.replace(' ', '-') 47 | str_lst.append("{}- [{}]({}#{})".format(" "*(h[0]-1)*2, h[1], fstruct['file'], hstr)) 48 | return '\n'.join(str_lst) 49 | 50 | def writetoc(toc, readmef): 51 | content = [] 52 | intoc = False 53 | f = open(readmef, 'rw+') 54 | for l in f: 55 | if not intoc: 56 | content.append(l) 57 | if l.strip() == "": 58 | content.append(toc) 59 | content.append('\n\n') 60 | intoc = True 61 | if l.strip() == "": 62 | intoc = False 63 | content.append(l) 64 | f.seek(0, os.SEEK_SET) 65 | f.truncate() 66 | f.write("".join(content)) 67 | f.close() 68 | 69 | if __name__ == "__main__": 70 | toc = [] 71 | for f in listfiles("docs"): 72 | fstruct = parsefile(f) 73 | toc.append(tomarkdown(fstruct)) 74 | writetoc("\n".join(toc), "./README.md") -------------------------------------------------------------------------------- /code/function_table.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | // Explicit instantiation of std::string needed, otherwise 7 | // we get a liner error with clang on osx thats a bug in libc++ 8 | // because of interaction with 9 | // __attribute__ ((__visibility__("hidden"), __always_inline__)) in std::string 10 | // Without this line, &std::string::empty will be in error of 'undefined symbols' 11 | template class std::basic_string; 12 | 13 | class Screen { 14 | public: 15 | using Action = Screen& (Screen::*) (); 16 | enum Directions { HOME, FORWARD, BACK, UP, DOWN }; 17 | 18 | Screen& home() { 19 | std::cout << "go to home\n"; 20 | return *this; 21 | } 22 | Screen& forward() { 23 | std::cout << "go to forward\n"; 24 | return *this; 25 | } 26 | Screen& back() { 27 | std::cout << "go to back\n"; 28 | return *this; 29 | } 30 | Screen& up() { 31 | std::cout << "go to up\n"; 32 | return *this; 33 | } 34 | Screen& down() { 35 | std::cout << "go to down\n"; 36 | return *this; 37 | } 38 | 39 | Screen& move(Directions); 40 | private: 41 | static Action menu[]; 42 | }; 43 | 44 | Screen& Screen::move(Directions cm) 45 | { 46 | return (this->*menu[cm])(); 47 | } 48 | 49 | Screen::Action Screen::menu[] = { 50 | &Screen::home, 51 | &Screen::forward, 52 | &Screen::back, 53 | &Screen::up, 54 | &Screen::down, 55 | }; 56 | 57 | int main() 58 | { 59 | Screen myScreen; 60 | myScreen.move(Screen::HOME); 61 | myScreen.move(Screen::UP); 62 | 63 | std::function fcn = &std::string::empty; 64 | std::function fp = &std::string::empty; 65 | 66 | // The callable generated by mem_fn can be called on either an object or 67 | // a pointer: 68 | std::vector svec{"", "second"}; 69 | auto f = std::mem_fn(&std::string::empty); 70 | f(*svec.begin()); 71 | if (f(&svec[0])) { 72 | std::cout << "first element of svec is empty.\n"; 73 | } 74 | 75 | // std::bind 76 | using std::placeholders::_1; 77 | auto fb = std::bind(&std::string::empty, _1); 78 | if (fb(*svec.begin())) { 79 | std::cout << "first element of svec is empty (bind).\n"; 80 | } 81 | f(&svec[0]); 82 | 83 | return 0; 84 | } 85 | -------------------------------------------------------------------------------- /code/associative_container.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | struct Sales_data { 9 | std::string isbn; 10 | }; 11 | 12 | size_t hasher(const Sales_data &sd) 13 | { 14 | return std::hash()(sd.isbn); 15 | } 16 | 17 | bool eqOp(const Sales_data &lhs, const Sales_data &rhs) 18 | { 19 | return lhs.isbn == rhs.isbn; 20 | } 21 | 22 | int main() 23 | { 24 | std::set::value_type v1; // v1 is a string 25 | std::set::key_type v2; // v2 is a string 26 | std::map::value_type v3; // v3 is a pair 27 | 28 | std::set iset = {0,1,2,3,4,5,6,7,8,9}; 29 | std::set::iterator set_it = iset.begin(); 30 | if (set_it != iset.end()) { 31 | //*set_it = 42; 32 | std::cout << *set_it << std::endl; 33 | } 34 | 35 | std::multimap authors; 36 | authors.insert({"Barth, John", "Sot-Weed Factor"}); 37 | authors.insert({"Barth, John", "Lost in the Funhouse"}); 38 | 39 | auto cnt = authors.erase("Barth, John"); 40 | std::cout << cnt << std::endl; 41 | 42 | std::set iset2 = {0,1,2,3,4,5,6,7,8,9}; 43 | std::cout << (iset2.find(1) == iset2.end()) << std::endl; 44 | std::cout << (iset2.find(11) == iset2.end()) << std::endl; 45 | std::cout << iset2.count(1) << std::endl; 46 | std::cout << iset2.count(11) << std::endl; 47 | 48 | // (1) 49 | std::string search_item("Alain de Botton"); 50 | auto entries = authors.count(search_item); 51 | auto iter = authors.find(search_item); 52 | while (entries) { 53 | std::cout << iter->second << std::endl; 54 | ++iter; 55 | --entries; 56 | } 57 | 58 | // (2) 59 | for (auto beg = authors.lower_bound(search_item), 60 | end = authors.upper_bound(search_item); 61 | beg != end; ++beg) { 62 | std::cout << beg->second << std::endl; 63 | } 64 | 65 | // (3) 66 | for (auto pos = authors.equal_range(search_item); pos.first != pos.second; 67 | ++pos.first) { 68 | std::cout << pos.first->second << std::endl; 69 | } 70 | 71 | using SD_multiset = std::unordered_multiset; 72 | SD_multiset bookstore(42, hasher, eqOp); 73 | 74 | return 0; 75 | } 76 | -------------------------------------------------------------------------------- /code/conversion_operator.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | class SmallInt { 6 | // Remove comment will cause ambiguity 7 | // friend SmallInt operator+(const SmallInt &lhs, const SmallInt &rhs); 8 | public: 9 | SmallInt(int i=0) : val(i) 10 | { 11 | if (i < 0 || i > 255) 12 | throw std::out_of_range("Bad SmallInt value"); 13 | } 14 | /* explicit */operator int() const { 15 | return val; 16 | } 17 | private: 18 | std::size_t val; 19 | }; 20 | 21 | /* 22 | SmallInt operator+(const SmallInt &lhs, const SmallInt &rhs) 23 | { 24 | return SmallInt(lhs.val + rhs.val); 25 | } 26 | */ 27 | 28 | // Preposition declaration 29 | struct B; 30 | struct A { 31 | A() = default; 32 | A(const B&) { 33 | std::cout << "A constructor from B" << std::endl; 34 | } 35 | }; 36 | struct B { 37 | operator A() const { 38 | std::cout << "B convert to A" << std::endl; 39 | return A(); 40 | } 41 | }; 42 | A f(const A& parameter) { 43 | return parameter; 44 | } 45 | 46 | //;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 47 | 48 | struct C { 49 | C(int x = 0) {} 50 | C(double x) {} 51 | operator int() const { return 0; } 52 | operator double() const { return 0; } 53 | }; 54 | 55 | void f2(long double) {} 56 | 57 | struct D { 58 | D(int) {} 59 | }; 60 | 61 | void manip(const C&) {} 62 | void manip(const D&) {} 63 | 64 | struct E { 65 | E(double); 66 | }; 67 | 68 | void manip2(const C&) {} 69 | void manip2(const E&) {} 70 | 71 | int main() 72 | { 73 | SmallInt si; 74 | si = 4; // implicitly converts 4 to SmallInt 75 | (void)(si + 3); // implicitly converts si to int 76 | 77 | SmallInt si2 = (int)3.14; // calls the SmallInt(int) constructor 78 | (void)(si2 + 3.14); // converts SmallInt to int, then converts to double 79 | 80 | B b; 81 | //A a = f(b); // There is no ambiguity under Cygwin compiler 82 | //(void)(a); 83 | 84 | f(b.operator A()); 85 | f(A(b)); 86 | 87 | // C c; 88 | // f2(c); // ambiguous; 89 | 90 | // long lg; 91 | // C c2(lg); // ambiguous; 92 | 93 | // Promoting short to int is better 94 | short s = 42; 95 | C c3(s); 96 | 97 | // Ambiguous: manip(C(10)), manip(D(10)) 98 | // manip(10); 99 | 100 | // Ambiguous: manip2(C(10)), manip2(E(double(10))) 101 | // manip2(10); 102 | 103 | return 0; 104 | } 105 | -------------------------------------------------------------------------------- /code/union_class.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class Token { 5 | public: 6 | Token() : tok(INT), ival{0} { } 7 | Token(const Token &t) : tok(t.tok) { copyUnion(t); } 8 | Token & operator=(const Token &); 9 | 10 | ~Token() { 11 | using std::string; 12 | if (tok == STR) 13 | sval.~string(); 14 | } 15 | 16 | Token & operator=(const std::string &); 17 | Token & operator=(char); 18 | Token & operator=(int); 19 | Token & operator=(double); 20 | 21 | private: 22 | enum { INT, CHAR, DBL, STR } tok; 23 | 24 | union { 25 | char cval; 26 | int ival; 27 | double dval; 28 | std::string sval; 29 | }; 30 | 31 | void copyUnion(const Token &); 32 | }; 33 | 34 | Token & Token::operator=(int i) 35 | { 36 | using std::string; 37 | if (tok == STR) 38 | sval.~string(); 39 | ival = i; 40 | tok = INT; 41 | return *this; 42 | } 43 | 44 | Token & Token::operator=(char c) 45 | { 46 | using std::string; 47 | if (tok == STR) 48 | sval.~string(); 49 | cval = c; 50 | tok = CHAR; 51 | return *this; 52 | } 53 | 54 | Token & Token::operator=(double d) 55 | { 56 | using std::string; 57 | if (tok == STR) 58 | sval.~string(); 59 | dval = d; 60 | tok = DBL; 61 | return *this; 62 | } 63 | 64 | Token & Token::operator=(const std::string &str) 65 | { 66 | if (tok == STR) 67 | sval = str; 68 | else 69 | // Use placement new to construct a string 70 | new (&sval) std::string(str); 71 | tok = STR; 72 | return *this; 73 | } 74 | 75 | void Token::copyUnion(const Token &t) { 76 | switch (t.tok) { 77 | case INT: 78 | ival = t.ival; 79 | break; 80 | case CHAR: 81 | cval = t.cval; 82 | break; 83 | case DBL: 84 | dval = t.dval; 85 | break; 86 | case STR: 87 | new (&sval) std::string(t.sval); 88 | break; 89 | } 90 | } 91 | 92 | Token & Token::operator=(const Token &rhs) { 93 | using std::string; 94 | if (tok == STR && rhs.tok != STR) 95 | sval.~string(); 96 | 97 | if (tok == STR && rhs.tok == STR) 98 | sval = rhs.sval; 99 | else 100 | copyUnion(rhs); 101 | tok = rhs.tok; 102 | return *this; 103 | } 104 | 105 | int main() 106 | { 107 | union { 108 | char cval; 109 | int ival; 110 | double dval; 111 | }; 112 | 113 | cval = 'c'; 114 | ival = 42; 115 | 116 | return 0; 117 | } 118 | -------------------------------------------------------------------------------- /code/func_return_type.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | std::string make_plural(size_t ctr, const std::string &word, const std::string &ending); 6 | const std::string &shorterString(const std::string &s1, const std::string &s2); 7 | const std::string &manip(); 8 | char &get_val(std::string &str, std::string::size_type ix); 9 | std::string Noreturn(); 10 | std::vector process(); 11 | 12 | class mystring { 13 | public: 14 | mystring() { 15 | std::cout << "mystring()" << std::endl; 16 | } 17 | mystring(const char *s) 18 | { 19 | std::cout << "mystring(const char *s)" << std::endl; 20 | } 21 | mystring(const mystring &rlh) { 22 | std::cout << "mystring(const mystring &rlh)" << std::endl; 23 | } 24 | void operator=(const mystring &rlh) 25 | { 26 | std::cout << "operator=(const mystring &rlh)" << std::endl; 27 | } 28 | }; 29 | 30 | int main(int argc, char *argv[]) 31 | { 32 | std::string s1 = "Very long string"; 33 | std::string s2 = "The short one"; 34 | auto &s = shorterString(s1, s2); 35 | auto sz = shorterString(s1, s2).size(); 36 | std::cout << sz << std::endl; 37 | std::string &s3 = const_cast(s); 38 | s3 = "Reference"; 39 | std::cout << s << std::endl; 40 | std::cout << s1 << std::endl; 41 | std::cout << s2 << std::endl; 42 | 43 | std::string s4("a value"); 44 | std::cout << s4 << std::endl; 45 | get_val(s4, 0) = 'A'; 46 | std::cout << s4 << std::endl; 47 | 48 | // 不返回任何值是未定义行为,不论结果类型是类类型还是内置类型 49 | //std::cout << "Noreturn: " << Noreturn() << std::endl; 50 | 51 | std::vector ret = process(); 52 | for (const auto &str : ret) 53 | std::cout << str << " "; 54 | std::cout << std::endl; 55 | 56 | return 0; 57 | } 58 | 59 | const std::string &shorterString(const std::string &s1, const std::string &s2) 60 | { 61 | return s1.size()1) ? word : ending; 67 | } 68 | 69 | const std::string &manip() 70 | { 71 | std::string ret; 72 | if (!ret.empty()) 73 | return ret; 74 | else 75 | return "Empty"; 76 | } 77 | 78 | char &get_val(std::string &str, std::string::size_type ix) { 79 | return str[ix]; 80 | } 81 | 82 | std::string Noreturn() {} 83 | 84 | std::vector process() { 85 | std::string expected("expected"); 86 | std::string actual = "actual"; 87 | if (expected.empty()) 88 | return {}; 89 | else if (expected == actual) 90 | return {"functionX", "okay"}; 91 | else 92 | return {"functionX", expected, actual}; 93 | } 94 | -------------------------------------------------------------------------------- /code/screen_window_mgr.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | class Screen { 6 | public: 7 | typedef std::string::size_type pos; 8 | // alternative way to declare a type member using a type alias 9 | //using pos = std::string::size_type; 10 | 11 | Screen() = default; 12 | 13 | Screen(pos ht, pos wd, char c) : 14 | height(ht), 15 | width(wd), 16 | contents(ht*wd, c) 17 | {} 18 | 19 | Screen(pos ht, pos wd): 20 | height(ht), 21 | width(wd), 22 | contents(ht*wd, ' ') 23 | {} 24 | 25 | char get() const 26 | { 27 | return contents[cursor]; 28 | } 29 | 30 | inline char get(pos ht, pos wd) const; 31 | 32 | Screen &move(pos r, pos c); 33 | 34 | void some_member() const; 35 | 36 | Screen &set(char c); 37 | Screen &set(pos r, pos col, char ch); 38 | 39 | Screen &display(std::ostream &os) 40 | { 41 | do_display(os); 42 | return *this; 43 | } 44 | 45 | const Screen &display(std::ostream &os) const 46 | { 47 | do_display(os); 48 | return *this; 49 | } 50 | private: 51 | void do_display(std::ostream &os) const; 52 | private: 53 | pos cursor = 0; 54 | pos height = 0, width = 0; 55 | std::string contents; 56 | 57 | mutable size_t access_ctr; 58 | }; 59 | 60 | ///////////////////////////////////////////////////////////// 61 | 62 | void Screen::do_display(std::ostream &os) const 63 | { 64 | for (pos i=0; i screens{Screen(24, 80, ' ')}; 106 | Screen default_screen_{}; 107 | }; 108 | 109 | int main() 110 | { 111 | Screen myscreen(24, 80, '*'); 112 | std::cout << myscreen.get() << std::endl; 113 | std::cout << myscreen.get(0, 0) << std::endl; 114 | myscreen.move(4, 0).set('#').display(std::cout); 115 | 116 | Screen blank(5, 3); 117 | blank.set('#').display(std::cout); 118 | return 0; 119 | } 120 | -------------------------------------------------------------------------------- /code/TextQuery.txt: -------------------------------------------------------------------------------- 1 | What users say:“Cheers for a great tool that actually makes programmers want to 2 | write documentation!“ 3 | Sphinx is a tool that makes it easy to create intelligent and beautiful 4 | documentation, written by Georg Brandl and licensed under the BSD license. 5 | It was originally created for the Python documentation, and it has excellent 6 | facilities for the documentation of software projects in a range of languages. 7 | Of course, this site is also created from reStructuredText sources using Sphinx! 8 | The following features should be highlighted: 9 | Output formats: HTML (including Windows HTML Help), LaTeX (for printable PDF 10 | versions), ePub, Texinfo, manual pages, plain text 11 | Extensive cross-references: semantic markup and automatic links for functions, 12 | classes, citations, glossary terms and similar pieces of information 13 | Hierarchical structure: easy definition of a document tree, with automatic links 14 | to siblings, parents and children 15 | Automatic indices: general index as well as a language-specific module indices 16 | Code handling: automatic highlighting using the Pygments highlighter 17 | Extensions: automatic testing of code snippets, inclusion of docstrings from 18 | Python modules (API docs), and more 19 | Contributed extensions: more than 50 extensions contributed by users in a second 20 | repository; most of them installable from PyPI 21 | 22 | 23 | Sphinx uses reStructuredText as its markup language, and many of its strengths 24 | come from the power and straightforwardness of reStructuredText and its parsing 25 | and translating suite, the Docutils. Documentation 26 | First steps with Sphinx 27 | overview of basic tasks 28 | Search page 29 | search the documentation 30 | Contents 31 | for a complete overview 32 | General Index 33 | all functions, classes, terms 34 | Changes 35 | release history 36 | You can also download PDF/EPUB versions of the Sphinx documentation from pop up 37 | menu on lower right corner.Examples 38 | Links to documentation generated with Sphinx can be found on the Projects using 39 | Sphinx page. 40 | For examples of how Sphinx source files look, use the “Show source” links on all 41 | pages of the documentation apart from this welcome page. 42 | You may also be interested in the very nice tutorial on how to create a customized 43 | documentation using Sphinx written by the matplotlib developers. 44 | There is a Japanese translation of this documentation, thanks to the Japanese Sphinx 45 | user group. 46 | A Japanese book about Sphinx has been published by O'Reilly: Sphinxをはじめよう / 47 | Learning Sphinx.Hosting 48 | Need a place to host your Sphinx docs? readthedocs.org hosts a lot of Sphinx docs 49 | already, and integrates well with projects' source control. It also features a 50 | powerful built-in search that exceeds the possibilities of Sphinx' JavaScript-based 51 | offline search.Contributor Guide 52 | If you want to contribute to the project, this part of the documentation is for you. 53 | Sphinx Developer’s Guide 54 | Sphinx Authors 55 | -------------------------------------------------------------------------------- /code/TextQueryComplicated.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "TextQueryComplicated.h" 12 | 13 | TextQuery::TextQuery(std::ifstream &in) : file(new std::vector) 14 | { 15 | std::string text; 16 | while (getline(in, text)) { 17 | file->push_back(text); 18 | int n = file->size() - 1; 19 | std::istringstream line(text); 20 | std::string word; 21 | while (line >> word) { 22 | auto &lines = wm[word]; 23 | if (!lines) { 24 | lines.reset(new std::set); 25 | } 26 | lines->insert(n); 27 | } 28 | } 29 | } 30 | 31 | QueryResult 32 | TextQuery::query(const std::string &word) const 33 | { 34 | static std::shared_ptr> nodata(new std::set{}); 35 | auto loc = wm.find(word); 36 | if (loc == wm.end()) { 37 | return QueryResult(word, nodata, file); 38 | } else 39 | return QueryResult(word, loc->second, file); 40 | } 41 | 42 | std::string 43 | make_plural(size_t ctr, const std::string &word, const std::string &ending) 44 | { 45 | return (ctr<=1)?word:word+ending; 46 | } 47 | 48 | std::ostream& print(std::ostream &os, const QueryResult &qr) 49 | { 50 | os << qr.sought << " occurs " << qr.lines->size() << " " 51 | << make_plural(qr.lines->size(), "time", "s") << std::endl; 52 | for (auto num : *qr.lines) { 53 | os << "\t(line " << num + 1 << ") " 54 | << *(qr.file->begin() + num) << std::endl; 55 | } 56 | return os; 57 | } 58 | 59 | QueryResult 60 | NotQuery::eval(const TextQuery &text) const 61 | { 62 | QueryResult result = query.eval(text); 63 | std::shared_ptr> ret_lines = std::make_shared>(); 64 | std::size_t size = result.get_file()->size(); 65 | auto beg = result.begin(), end = result.end(); 66 | for (std::size_t n=0; n != size; n++) 67 | { 68 | if (beg == end || n != *beg) { 69 | ret_lines->insert(n); 70 | } else if (beg != end) { 71 | beg++; 72 | } 73 | } 74 | return QueryResult(rep(), ret_lines, result.get_file()); 75 | } 76 | 77 | QueryResult 78 | AndQuery::eval(const TextQuery &text) const 79 | { 80 | auto left = lhs.eval(text), right = rhs.eval(text); 81 | auto ret_lines = std::make_shared>(); 82 | std::set_intersection(left.begin(), left.end(), 83 | right.begin(), right.end(), 84 | std::inserter(*ret_lines, ret_lines->begin())); 85 | return QueryResult(rep(), ret_lines, left.get_file()); 86 | } 87 | 88 | QueryResult 89 | OrQuery::eval(const TextQuery &text) const 90 | { 91 | auto left = lhs.eval(text), right = rhs.eval(text); 92 | auto ret_lines = std::make_shared>(left.begin(), right.end()); 93 | ret_lines->insert(right.begin(), right.end()); 94 | return QueryResult(rep(), ret_lines, left.get_file()); 95 | } 96 | -------------------------------------------------------------------------------- /code/use_string.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | const char *cp = "Hello world!!!"; 7 | char noNull[] = {'H','i'}; 8 | 9 | std::string s1(cp); 10 | std::string s2(noNull, 2); 11 | 12 | //:Caution: noNull not null terminated 13 | //std::string s3(noNull); 14 | std::string s4(cp+6, 5); 15 | 16 | // 6 is start index, not number of elements for copy 17 | std::string s5(s1, 6, 5); 18 | std::string s6(s1, 6); 19 | std::string s7(s1, 6, 20); 20 | 21 | //:Caution: 16 is out of range 22 | //std::string s8(s1, 16); 23 | 24 | // undefined means there is runtime error that compiler can't detect, 25 | // and doesn't cause program crash. 26 | 27 | std::string s("hello world"); // size == 11 28 | std::string s9 = s.substr(0, 5); // string.substr(pos, n) 29 | std::string s10 = s.substr(6); 30 | std::string s11 = s.substr(6, 11); 31 | 32 | //:Caution: 12 is out of range 33 | //std::string s12 = s.substr(12); // out of range 34 | 35 | // The index indicates the starting element of erase or the position before 36 | // which to insert the given values: 37 | s.insert(s.size(), 5, '!'); 38 | std::cout << "s: " << s << std::endl; 39 | s.erase(s.size() - 5, 5); 40 | 41 | const char *cp1 = "Stately, plump Buck"; 42 | s.assign(cp1, 7); // string.assign(s, count) 43 | s.insert(s.size(), cp1+7); //string.insert(index, s) 44 | 45 | std::string s12 = "some string", s13 = "some other string"; 46 | s12.insert(0, s13); 47 | s12.insert(0, s13, 0, s13.size()); 48 | 49 | // String defines append and replace functions 50 | std::string s15("C++ Primer"), s14 = s15; 51 | s15.insert(s15.size(), " 4th Ed."); 52 | s14.append(" 4th Ed."); 53 | // replace is shorthand way of calling erase and insert 54 | s15.erase(11, 3); 55 | s15.insert(11, "5th"); 56 | s15.replace(11, 3, "5th"); 57 | s15.replace(11, 3, "Fifth"); 58 | 59 | std::string name("AnnaBelle"); 60 | auto pos1 = name.find("Anna"); 61 | std::cout << "find: " << pos1 << std::endl; 62 | 63 | std::string lowercase("annabelle"); 64 | pos1 = lowercase.find("Anna"); 65 | std::cout << "not found: " << (pos1 == std::string::npos) << std::endl; 66 | 67 | std::string numbers("0123456789"), name1("r2d2"); 68 | auto pos = name1.find_first_of(numbers); 69 | std::cout << "find number: " << pos << std::endl; 70 | 71 | std::string dept("03714p3"); 72 | pos = dept.find_first_not_of(numbers); 73 | std::cout << "find not number: " << pos << std::endl; 74 | 75 | // Common programming pattern to continue use pos 76 | std::string::size_type pos2 = 0; 77 | while ((pos2 = name1.find_first_of(numbers,pos2)) != std::string::npos) { 78 | std::cout << "found number at index: " << pos2 79 | << " element is " << name1[pos2] << std::endl; 80 | ++pos2; 81 | } 82 | 83 | std::string river("Mississippi"); 84 | auto first_pos = river.find("is"); 85 | auto last_pos = river.rfind("is"); 86 | std::cout << "first_pos: " << first_pos << " last_pos: " << last_pos << std::endl; 87 | 88 | int i = 42; 89 | std::string s3 = std::to_string(i); 90 | double d = stod(s3); 91 | std::cout << d << std::endl; 92 | 93 | std::string str1 = "pi = 3.14"; 94 | d = stod(str1.substr(str1.find_first_of("+-.0123456789"))); 95 | std::cout << d << std::endl; 96 | 97 | return 0; 98 | } 99 | -------------------------------------------------------------------------------- /code/overview_of_algorithms.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | void elimDups(std::vector &words) 10 | { 11 | std::sort(words.begin(), words.end()); 12 | auto end_unique = std::unique(words.begin(), words.end()); 13 | words.erase(end_unique, words.end()); 14 | } 15 | 16 | bool isShorter(const std::string &s1, const std::string &s2) 17 | { 18 | return s1.size() < s2.size(); 19 | } 20 | 21 | std::string 22 | make_plural(size_t ctr, const std::string &word, const std::string &ending) 23 | { 24 | return (ctr<=1)?word:word+ending; 25 | } 26 | 27 | void biggies(std::vector &words, std::vector::size_type sz) 28 | { 29 | elimDups(words); 30 | std::stable_sort(words.begin(), words.end(), isShorter); 31 | auto wc = std::find_if(words.begin(), words.end(), 32 | [sz](const std::string &a) { return a.size() >= sz; }); 33 | auto count = words.end() - wc; 34 | std::cout << count << " " << make_plural(count, "word", "s") 35 | << " of lenght " << sz << " or longer" << std::endl; 36 | std::for_each(wc, words.end(), [](const std::string &s) { 37 | std::cout << s << " "; 38 | }); 39 | std::cout << std::endl; 40 | } 41 | 42 | int main() 43 | { 44 | int val = 32; 45 | std::vector vec{1, 2, 3, 32, 4, 5, 6}; 46 | auto result = std::find(vec.cbegin(), vec.cend(), val); 47 | std::cout << "The value " << val << (result == vec.cend() ? " is not present" 48 | : " is present") << std::endl; 49 | 50 | std::list lst{"hello","world","a value","string","b value"}; 51 | std::string sval = "d value"; 52 | auto sresult = std::find(lst.cbegin(), lst.cend(), sval); 53 | std::cout << "svalue '" << sval << "'" << (sresult == lst.cend() ? " is not present" 54 | : " is present") << std::endl; 55 | 56 | int ia[] = {27, 210, 12, 47, 109, 83}; 57 | int ival = 83; 58 | int *iresult = std::find(std::begin(ia), std::end(ia), ival); 59 | std::cout << *iresult << std::endl; 60 | // Search the elements starting from ia[1] up to but not including ia[4] 61 | auto iresult2 = std::find(ia+1, ia+4, ival); 62 | std::cout << (iresult2 == ia+4 ? "not found" : "found") << std::endl; 63 | 64 | int sum = std::accumulate(vec.cbegin(), vec.cend(), 0); 65 | std::cout << "sum of vec: " << sum << std::endl; 66 | 67 | std::string ssum = std::accumulate(lst.cbegin(), lst.cend(), std::string("")); 68 | std::cout << "concatenation of lst: " << ssum << std::endl; 69 | 70 | std::cout << "======================\n"; 71 | std::vector ivec; 72 | auto it = std::back_inserter(ivec); 73 | for (int i=0; i != 10; i++) { 74 | *it++ = 42+i; 75 | } 76 | std::fill_n(back_inserter(ivec), 10, 2); 77 | std::for_each(ivec.cbegin(), ivec.cend(), [](int i) { 78 | std::cout << i << std::endl; 79 | }); 80 | 81 | std::vector words{"the","quick","red","fox","jumps","over","the","slow","red","turtle"}; 82 | elimDups(words); 83 | std::stable_sort(words.begin(), words.end(), isShorter); 84 | using namespace std::placeholders; 85 | std::stable_sort(words.begin(), words.end(), std::bind(isShorter, _2, _1)); 86 | std::for_each(words.cbegin(), words.cend(), [](const std::string &str) { 87 | std::cout << str << " "; 88 | }); 89 | std::cout << "\n"; 90 | biggies(words, 4); 91 | 92 | return 0; 93 | } 94 | -------------------------------------------------------------------------------- /docs/CH05_Statements.md: -------------------------------------------------------------------------------- 1 | C++ 定义了表达式语句(expression statement)与声明语句(declaration statement)和控制语句(flow-of-control statement)以及空语句(empty statement)。 2 | 3 | 表达式语句就是表达式后跟一个分号,其对表达式进行求值并将结果抛弃,通常表达式语句会产生副作用(size effect)如:赋值、输入输出等。 4 | 5 | 声明语句则是声明各种变量,这在几章中进行过详细的描述。 6 | 7 | 控制语句包括:if 语句、switch 语句、while 语句、do-while 语句以及 for 语句。这些语句跟 C 、Java 语言中的结构几乎完全一致,一致的部分不再给出。 8 | 9 | 空语句就是一个分号,本身不具有任何功能,当语言要求必须有一条语句而又没有可执行的操作时就可以写一条空语句。 10 | 11 | 以上语句加上 {} 大括号构成复合语句(compound statement)或者称为块(block)。块引入一个新的作用域,定义在此作用域中的名字只能在此作用域或其子作用域中可见。名字从声明位置到块结束的右括号为止。这种复合语句与简单语句是可以互换的,通常当逻辑上需要多条语句,而语言只允许一条语句时就会使用复合语句。 12 | 13 | # if 语句 14 | 15 | if 语句需要注意悬决 else(dangling else) 问题,即 else 只与最近的 if 匹配,如果不是这样,需要使用括号强制匹配。 16 | 17 | # switch 语句 18 | 19 | case 标签中的值必须是整型常量表达式,并且不能有任何两个 case 具有相同的值。当 switch 选中一个 case 后会一直执行到最后,如果需要只执行一个 case 则需要主动使用 break 。switch 语句中涉及到跳过代码,C++ 语言要求一定不能跳过变量的定义而直接跳到使用的地方。如: 20 | ````cpp 21 | int val = 1; 22 | switch(val) { 23 | case 0: 24 | int passby = 0; 25 | break; 26 | case 1: 27 | ++passby; //错误!! 跳过了定义,而直接使用变量 passby 28 | break; 29 | } 30 | ```` 31 | 32 | # while 语句 33 | 34 | 注意 while 条件或循环体中定义的变量,在每次循环时会重新定义和销毁。 35 | 36 | # do-while 语句 37 | 38 | 需要注意在 do 循环体中定义的变量,无法在条件中访问。do-while 语句至少会执行一次。 39 | 40 | # for 语句 41 | 42 | for 分为两种:传统 for 和范围 for。传统 for 就是 C 风格的 for,头部形如:`for(initializer;condition;expression)`其中 for 头部中的三个部分都可以省略,此时循环体就会无限执行。在 C++ 中 initializer 中定义的变量当循环结束时会被销毁,而在 C89 中并不会,C99 行为与 C++ 一样。 43 | 44 | 范围 for 形如:`for (declaration : expression)` 其中表达式可以是大括号中的初始列表(initializer list)、数组、或者容器类或 string 类等能够被遍历的序列类型。declaration 中定义的变量类型必须与序列中元素类型一致,最常用的方式是用 auto 声明变量,如果希望改变序列中的值,将循环变量类型定义为引用类型。每次循环时,循环变量都会被初始化为下一个元素的值。 45 | 46 | # goto 语句 47 | 48 | goto 语句用于在同一个函数内跳转。goto 跳转需要给出一个标签,这个标签在一条语句的头部,形成标签语句(labeled statement)。形如: 49 | ````cpp 50 | goto label; 51 | label: statement; 52 | ```` 53 | 其中标签独立于语言中的任何别的类别的标识符,即便是与它们重名亦是可以的。与 switch 一样,不可以跳过变量的定义而直接到使用的位置。如果是向后跳转则将跳过部分的变量销毁。 54 | 55 | # 异常处理 56 | 57 | 在 C++ 中进行异常处理是很难做到干净而简单的,其根本原因在于 C++ 中的对象是由程序员管理的。而抛出异常之后需要将申请的资源以及内存回收,C++ 除了会回收局部对象外并不做额外的工作。C++ 的异常机制没有 finally 子句,原因在于 C++ 有 RAII(Resource Acquisition Is Initialization)获取资源即初始化,当对象销毁时将自动释放资源。 58 | 59 | C++ 允许抛出任何类型的对象而不仅仅是 exception 及其子类。C++ 抛出的对象不需要 new ,因而,编译器会将其放到一个特殊的位置中,从而可以在不同的调用栈层次进行匹配检查。throw 子句通常构造一个对象,将这个对象放到编译器的特殊位置中。catch 子句中包含一个对象声明,当匹配时编译器将抛出的对象复制到声明对象中,如果声明为引用则将其初始化为抛出对象的引用。当 catch 子句结束时,声明的对象将先被销毁,然后抛出对象也被销毁。重新抛出对象只要 `throw;` 即可,此时会将同一个异常对象再次抛出,如果声明为引用并且改变了此异常对象,那么再次抛出的就是改变后的对象。 60 | 61 | 查看:[throw.cpp](https://github.com/chuenlungwang/cppprimer-note/blob/master/code/throw.cpp) 了解示例代码。 62 | 63 | C++ 的异常匹配与 Java 中的一样,将最匹配最先找到的 catch 子句,而不是精确匹配,所以应当将最具体的异常类放在最前面。另外需要注意的一点是在 try 块中声明的对象是不能在 catch 中访问的。 64 | 65 | ## 警告:C++ 中很难达到异常安全 66 | 67 | 当异常发生时将打断程序的正常执行流,此时某些计算还未完成,这样便将一些对象置于非法或者不完全状态,或者资源没有被释放。程序必须正确的清理所有这些才算是异常安全。需要处理异常的程序需要时刻谨记可能出现的异常,以及必须采取的步骤来保证对象处于安全的状态以及资源不会泄露,并且将程序恢复到正确的状态。 68 | 69 | ## 标准异常 70 | 71 | exception 是所有标准异常的基类,定义在 exception 头文件中。stdexcept 头文件中定义了诸如: 72 | 73 | - `runtime_error` 运行时错误; 74 | - `range_error` 运行时错误,产生的结果超出有效值范围; 75 | - `overflow_error` 运行时错误,计算上溢; 76 | - `underflow_error` 运行时错误,计算下溢; 77 | - `logic_error` 程序逻辑错误; 78 | - `domain_error` 逻辑错误,在给定参数的情况下无法生成结果; 79 | - `invalid_argument` 逻辑错误,非法参数; 80 | - `length_error` 逻辑错误,试图生成一个操作最大尺寸的独享; 81 | - `out_of_range` 逻辑错误,参数超出合法值的范围; 82 | 83 | 具体参考网页:[https://en.cppreference.com/w/cpp/error/exception](https://en.cppreference.com/w/cpp/error/exception) 84 | 85 | 标准库中的异常只有少数操作:创建、复制、赋值,其中 `exception` `bad_alloc` `bad_cast` 只有默认构造函数。其它类型的异常只有一个接收字符串的构造函数用来说明异常信息,这些异常信息可以通过调用异常的 `what()` 成员函数来取得。 -------------------------------------------------------------------------------- /code/random.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void 8 | default_random_engine() 9 | { 10 | std::default_random_engine e; 11 | for (size_t i = 0; i < 10; ++i) 12 | std::cout << e() << std::endl; 13 | std::cout << "min: " << e.min() << std::endl; 14 | std::cout << "max: " << e.max() << std::endl; 15 | } 16 | 17 | void 18 | distribution_of_random() 19 | { 20 | std::uniform_int_distribution u(0, 9); 21 | std::default_random_engine e; 22 | for (size_t i = 0; i < 10; ++i) 23 | std::cout << u(e) << " " ; 24 | } 25 | 26 | std::vector bad_randVec() 27 | { 28 | //We should make engine and distribution static 29 | std::default_random_engine e; 30 | std::uniform_int_distribution u(0, 9); 31 | std::vector ret; 32 | for (size_t i = 0; i < 100; ++i) 33 | ret.push_back(u(e)); 34 | return ret; 35 | } 36 | 37 | std::vector 38 | good_randVec() 39 | { 40 | static std::default_random_engine e; 41 | static std::uniform_int_distribution u(0, 9); 42 | std::vector ret; 43 | for (size_t i = 0; i < 100; ++i) 44 | ret.push_back(u(e)); 45 | return ret; 46 | } 47 | 48 | void 49 | random_set_seed() 50 | { 51 | std::default_random_engine e1; 52 | std::default_random_engine e2(2147483646); 53 | std::default_random_engine e3; 54 | e3.seed(32767); 55 | std::default_random_engine e4(32767); 56 | for (size_t i=0; i!=100; ++i) { 57 | if (e1() == e2()) 58 | std::cout << "unseeded match at iteration: " << i << std::endl; 59 | if (e3() != e4()) 60 | std::cout << "seeded differs at iteration: " << i << std::endl; 61 | } 62 | } 63 | 64 | void test_real_random() 65 | { 66 | std::default_random_engine e; 67 | std::uniform_real_distribution u(0, 1); 68 | for (size_t i=0; i<10; ++i) 69 | std::cout << u(e) << " "; 70 | std::cout << std::endl; 71 | } 72 | 73 | void test_normal_distribution() 74 | { 75 | std::default_random_engine e; 76 | std::normal_distribution<> n(4, 1.5); 77 | std::vector values(9); 78 | for (size_t i=0; i != 200; ++i) { 79 | unsigned v = lround(n(e)); 80 | if (v < values.size()) 81 | ++values[v]; 82 | } 83 | for (size_t j=0; j!=values.size(); ++j) 84 | std::cout << j << ": " << std::string(values[j], '*') << std::endl; 85 | } 86 | 87 | bool play(bool first) { 88 | if (first) { 89 | return first; 90 | } 91 | } 92 | 93 | void test_bernoulli_distribution() 94 | { 95 | static std::default_random_engine e; 96 | static std::bernoulli_distribution b; 97 | for (int i=0; i!=20; i++) { 98 | bool first = b(e); 99 | std::cout << (first ? "We go first" 100 | : "You get to go first") 101 | << std::endl; 102 | std::cout << ((play(first)) ? "sorry, you lost" 103 | : "congrats, you won") 104 | << std::endl; 105 | } 106 | 107 | for (int i=0; i<99; i++) { 108 | std::bernoulli_distribution c(0.55); 109 | std::cout << c(e) << std::endl; 110 | } 111 | } 112 | 113 | int 114 | main() 115 | { 116 | default_random_engine(); 117 | distribution_of_random(); 118 | 119 | std::vector v1(bad_randVec()); 120 | std::vector v2(bad_randVec()); 121 | std::cout << ((v1 == v2) ? "equal" : "not equal") << std::endl; 122 | 123 | std::vector v3(good_randVec()); 124 | std::vector v4(good_randVec()); 125 | std::cout << ((v3 == v4) ? "equal" : "not equal") << std::endl; 126 | 127 | random_set_seed(); 128 | test_real_random(); 129 | std::uniform_real_distribution<> u(0, 1); 130 | test_normal_distribution(); 131 | test_bernoulli_distribution(); 132 | 133 | return 0; 134 | } 135 | -------------------------------------------------------------------------------- /code/io_revisit.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void 7 | format_of_boolean_values() 8 | { 9 | std::cout << "default bool values: " << true << " " << false 10 | << "\nalpha bool values: " << std::boolalpha 11 | << true << " " << false << std::noboolalpha << std::endl; 12 | } 13 | 14 | void 15 | base_for_integral_values() 16 | { 17 | std::cout << std::showbase << std::uppercase; 18 | std::cout << "default: " << 20 << " " << 1024 << std::endl; 19 | std::cout << "octal: " << std::oct << 20 << " " << 1024 << std::endl; 20 | std::cout << "hex: " << std::hex << 20 << " " << 1024 << std::endl; 21 | std::cout << "decimal: " << std::dec << 20 << " " << 1024 << std::endl; 22 | std::cout << std::nouppercase << std::noshowbase << std::dec; 23 | } 24 | 25 | void 26 | control_precision_of_float_point() 27 | { 28 | int precision = std::cout.precision(); 29 | std::cout << "Precision: " << std::cout.precision() 30 | << ", Value: " << sqrt(2.0) << std::endl; 31 | std::cout.precision(12); 32 | //std::cout << std::scientific; 33 | std::cout << "Precision: " << std::cout.precision() 34 | << ", Value: " << sqrt(2.0) << std::endl; 35 | std::cout << std::setprecision(3); 36 | std::cout << std::defaultfloat; 37 | std::cout << "Precision: " << std::cout.precision() 38 | << ", Value: " << sqrt(2.0) << std::endl; 39 | std::cout.precision(precision); 40 | } 41 | 42 | void 43 | another_control_precision_of_float_point() 44 | { 45 | double num = 100 * sqrt(2.0); 46 | std::cout << "default format: " << num << '\n' 47 | << "scientific: " << std::scientific << num << '\n' 48 | << "fixed decimal: " << std::fixed << num << '\n' 49 | << "hexadecimal: " << std::hexfloat << num << '\n' 50 | << "use defaults: " << std::defaultfloat << num << "\n\n"; 51 | } 52 | 53 | void 54 | showpoint_of_io() 55 | { 56 | std::cout << 10.0 << std::endl; 57 | std::cout << std::showpoint << 10.0 58 | << std::noshowpoint << std::endl; 59 | } 60 | 61 | void 62 | padding_the_output() 63 | { 64 | int i = -16; 65 | double d = 3.14159; 66 | std::cout << "i: " << std::setw(12) << i << " | next col" << '\n' 67 | << "d: " << std::setw(12) << d << " | next col" << '\n'; 68 | 69 | std::cout << std::left; 70 | std::cout << "i: " << std::setw(12) << i << " | next col" << '\n' 71 | << "d: " << std::setw(12) << d << " | next col" << '\n'; 72 | 73 | std::cout << std::right; 74 | std::cout << "i: " << std::setw(12) << i << " | next col" << '\n' 75 | << "d: " << std::setw(12) << d << " | next col" << '\n'; 76 | 77 | std::cout << std::internal; 78 | std::cout << "i: " << std::setw(12) << i << " | next col" << '\n' 79 | << "d: " << std::setw(12) << d << " | next col" << '\n'; 80 | 81 | std::cout << std::setfill('#'); 82 | std::cout << "i: " << std::setw(12) << i << " | next col" << '\n' 83 | << "d: " << std::setw(12) << d << " | next col" << '\n'; 84 | std::cout << std::setfill(' '); 85 | } 86 | 87 | void 88 | skip_input_whitespace() 89 | { 90 | std::istringstream is("ab c\nd\n"); 91 | is >> std::noskipws; 92 | char ch; 93 | while (is >> ch) 94 | std::cout << ch; 95 | is >> std::skipws; 96 | } 97 | 98 | void 99 | single_byte_operation() 100 | { 101 | char ch; 102 | std::istringstream is("ab c\nd\n"); 103 | while (is.get(ch)) 104 | std::cout.put(ch); 105 | } 106 | 107 | void 108 | get_return_int_value() 109 | { 110 | int ch; 111 | std::istringstream is("ab c\nd\n"); 112 | while ((ch = is.get()) != EOF) 113 | std::cout.put(ch); 114 | } 115 | 116 | int main() 117 | { 118 | format_of_boolean_values(); 119 | base_for_integral_values(); 120 | control_precision_of_float_point(); 121 | another_control_precision_of_float_point(); 122 | showpoint_of_io(); 123 | padding_the_output(); 124 | skip_input_whitespace(); 125 | single_byte_operation(); 126 | return 0; 127 | } 128 | -------------------------------------------------------------------------------- /code/message.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | class Folder; 6 | 7 | class Message { 8 | friend class Folder; 9 | friend void swap(Message &lhs, Message &rhs); 10 | public: 11 | explicit Message(const std::string &str = ""): 12 | contents(str) {} 13 | Message(const Message &); 14 | Message(Message &&m); 15 | Message& operator=(const Message &); 16 | Message& operator=(Message &&rhs); 17 | ~Message(); 18 | 19 | void save(Folder &); 20 | void remove(Folder &); 21 | private: 22 | void add_to_Folders(); 23 | void remove_from_Folders(); 24 | void move_Folders(Message *); 25 | private: 26 | std::string contents; 27 | std::set folders; 28 | }; 29 | 30 | ///////////////////////////////////////////////////////////// 31 | 32 | class Folder { 33 | friend void swap(Folder &lhs, Folder &rhs); 34 | public: 35 | void addMsg(Message *); 36 | void remMsg(Message *); 37 | 38 | Folder(const Folder &); 39 | Folder& operator=(const Folder &); 40 | ~Folder(); 41 | private: 42 | void add_Messages(); 43 | void remove_Messages(); 44 | private: 45 | std::set messages; 46 | }; 47 | 48 | ////////////////////////////////////////////////////////////// 49 | 50 | void Message::save(Folder &f) 51 | { 52 | folders.insert(&f); 53 | f.addMsg(this); 54 | } 55 | 56 | void Message::remove(Folder &f) 57 | { 58 | folders.erase(&f); 59 | f.remMsg(this); 60 | } 61 | 62 | void Message::add_to_Folders() 63 | { 64 | for (auto f : folders) 65 | f->addMsg(this); 66 | } 67 | 68 | void Message::remove_from_Folders() 69 | { 70 | for (auto f : folders) 71 | f->remMsg(this); 72 | } 73 | 74 | void Message::move_Folders(Message *m) 75 | { 76 | folders = std::move(m->folders); 77 | for (auto f : folders) { 78 | f->remMsg(m); 79 | f->addMsg(this); 80 | } 81 | m->folders.clear(); 82 | } 83 | 84 | Message::Message(const Message &msg): 85 | contents(msg.contents), 86 | folders(msg.folders) 87 | { 88 | add_to_Folders(); 89 | } 90 | 91 | Message::Message(Message &&msg):contents(std::move(msg.contents)) 92 | { 93 | move_Folders(&msg); 94 | } 95 | 96 | Message::~Message() 97 | { 98 | remove_from_Folders(); 99 | } 100 | 101 | Message& 102 | Message::operator=(const Message &rhs) 103 | { 104 | if (this == &rhs) 105 | return *this; 106 | remove_from_Folders(); 107 | contents = rhs.contents; 108 | folders = rhs.folders; 109 | add_to_Folders(); 110 | return *this; 111 | } 112 | 113 | Message& 114 | Message::operator=(Message &&rhs) 115 | { 116 | if (this == &rhs) 117 | return *this; 118 | remove_from_Folders(); 119 | contents = std::move(rhs.contents); 120 | move_Folders(&rhs); 121 | return *this; 122 | } 123 | 124 | void swap(Message &lhs, Message &rhs) 125 | { 126 | lhs.remove_from_Folders(); 127 | rhs.remove_from_Folders(); 128 | using std::swap; 129 | swap(lhs.contents, rhs.contents); 130 | swap(lhs.folders, rhs.folders); 131 | lhs.add_to_Folders(); 132 | rhs.add_to_Folders(); 133 | } 134 | 135 | ////////////////////////////////////////////////////////////// 136 | 137 | void Folder::addMsg(Message *msg) 138 | { 139 | messages.insert(msg); 140 | } 141 | 142 | void Folder::remMsg(Message *msg) 143 | { 144 | messages.erase(msg); 145 | } 146 | 147 | void 148 | Folder::remove_Messages() 149 | { 150 | for (auto *m : messages) 151 | m->remove(*this); 152 | } 153 | 154 | void 155 | Folder::add_Messages() 156 | { 157 | for (auto *m : messages) 158 | m->save(*this); 159 | } 160 | 161 | Folder::~Folder() 162 | { 163 | remove_Messages(); 164 | } 165 | 166 | Folder::Folder(const Folder &f): messages(f.messages) 167 | { 168 | add_Messages(); 169 | } 170 | 171 | Folder& 172 | Folder::operator=(const Folder &rhs) 173 | { 174 | if (this == &rhs) 175 | return *this; 176 | remove_Messages(); 177 | messages = rhs.messages; 178 | add_Messages(); 179 | return *this; 180 | } 181 | 182 | void swap(Folder &lhs, Folder &rhs) 183 | { 184 | using std::swap; 185 | lhs.remove_Messages(); 186 | rhs.remove_Messages(); 187 | swap(lhs.messages, rhs.messages); 188 | lhs.add_Messages(); 189 | rhs.add_Messages(); 190 | } 191 | -------------------------------------------------------------------------------- /code/function_call_operator.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | struct absInt { 8 | int operator()(int val) const { 9 | return val < 0 ? -val : val; 10 | } 11 | }; 12 | 13 | class PrintString { 14 | public: 15 | PrintString(std::ostream &o = std::cout, char c = ' '): 16 | os(o), sep(c) {} 17 | void operator()(const std::string &s) const 18 | { 19 | os << s << sep; 20 | } 21 | private: 22 | std::ostream &os; 23 | char sep; 24 | }; 25 | 26 | class ShorterString { 27 | public: 28 | bool operator()(const std::string &s1, const std::string &s2) const 29 | { 30 | return s1.size() < s2.size(); 31 | } 32 | }; 33 | 34 | class SizeComp { 35 | public: 36 | SizeComp(size_t n) : sz(n) {} 37 | bool operator()(const std::string &s) const 38 | { 39 | return s.size() >= sz; 40 | } 41 | private: 42 | size_t sz; 43 | }; 44 | 45 | int add(int i, int j) { 46 | return i+j; 47 | } 48 | 49 | auto mod = [](int i, int j) { return i%j; }; 50 | 51 | struct Div { 52 | int operator()(int denominator, int divisor) { 53 | return denominator / divisor; 54 | } 55 | }; 56 | 57 | int main() 58 | { 59 | int i = -42; 60 | absInt absObj; 61 | int ui = absObj(i); 62 | 63 | std::cout << ui << std::endl; 64 | 65 | PrintString errors(std::cerr, '\n'); 66 | errors("Something Wrong"); 67 | 68 | PrintString printer; 69 | printer("Makefile"); 70 | 71 | std::vector vs = {"friends", "developers", "notes"}; 72 | std::for_each(vs.begin(), vs.end(), errors); 73 | std::cout << "==========================\n"; 74 | 75 | std::stable_sort( 76 | vs.begin(), 77 | vs.end(), 78 | [](const std::string &a, const std::string &b) { 79 | return a.size() < b.size(); 80 | } 81 | ); 82 | std::stable_sort(vs.begin(), vs.end(), ShorterString()); 83 | std::for_each(vs.begin(), vs.end(), errors); 84 | 85 | std::cout << "==============================\n"; 86 | 87 | size_t sz = 5; 88 | auto wc = std::find_if( 89 | vs.begin(), 90 | vs.end(), 91 | [sz](const std::string &a) { 92 | return a.size() >= sz; 93 | } 94 | ); 95 | std::cout << *wc << std::endl; 96 | wc = std::find_if(vs.begin(), vs.end(), SizeComp(6)); 97 | std::cout << *wc << std::endl; 98 | 99 | std::plus intAdd; 100 | std::negate intNegate; 101 | int sum = intAdd(10, 20); 102 | std::cout << sum << std::endl; 103 | sum = intNegate(intAdd(10, 20)); 104 | std::cout << sum << std::endl; 105 | sum = intAdd(10, intNegate(10)); 106 | std::cout << sum << std::endl; 107 | 108 | std::sort(vs.begin(), vs.end(), std::greater()); 109 | std::cout << "==========================" << std::endl; 110 | 111 | std::vector nameTable{ 112 | new std::string("zoro"), 113 | new std::string("chanlion"), 114 | new std::string("hammer") 115 | }; 116 | 117 | // Sorted by pointer value not string value? 118 | std::sort(nameTable.begin(), nameTable.end(), std::less()); 119 | //std::for_each(nameTable.begin(), nameTable.end(), errors); 120 | for (std::string *s : nameTable) { 121 | std::cout << *s << std::endl; 122 | } 123 | 124 | std::function f1 = add; 125 | std::function f2 = Div(); 126 | std::function f3 = mod; 127 | std::function f4 = [](int i, int j) { 128 | return i * j; 129 | }; 130 | std::cout << f1(4, 2) << std::endl; 131 | std::cout << f2(4, 2) << std::endl; 132 | std::cout << f3(4, 2) << std::endl; 133 | std::cout << f4(4, 2) << std::endl; 134 | 135 | // ld error: Overloaded functions cann't add to map 136 | // double add(double i, double j); 137 | 138 | std::map> binops = { 139 | { "+", add }, // ?add 140 | { "-", std::minus() }, 141 | { "/", f2 }, 142 | { "*", f4 }, 143 | { "%", mod }, 144 | }; 145 | 146 | int (*fp)(int, int) = add; 147 | 148 | // To avert ambiguity 149 | // binops.insert({ "+", fp }); 150 | // binops.insert({ "+", [](int a, int b) { return add(a, b); } }); 151 | 152 | std::cout << binops["+"](10, 5) << std::endl; 153 | std::cout << binops["-"](10, 5) << std::endl; 154 | std::cout << binops["/"](10, 5) << std::endl; 155 | std::cout << binops["*"](10, 5) << std::endl; 156 | std::cout << binops["%"](10, 5) << std::endl; 157 | 158 | return 0; 159 | } 160 | -------------------------------------------------------------------------------- /code/TextQueryComplicated.h: -------------------------------------------------------------------------------- 1 | #ifndef __TEXT_QUERY_H__ 2 | #define __TEXT_QUERY_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | class QueryResult; 14 | 15 | class TextQuery { 16 | public: 17 | using line_no = std::vector::size_type; 18 | explicit TextQuery(std::ifstream &); 19 | public: 20 | QueryResult query(const std::string &) const; 21 | private: 22 | std::shared_ptr> file; 23 | std::map>> wm; 24 | }; 25 | 26 | class QueryResult { 27 | friend std::ostream& print(std::ostream&, const QueryResult&); 28 | public: 29 | QueryResult(std::string s, 30 | std::shared_ptr> p, 31 | std::shared_ptr> f) 32 | : sought(s), 33 | lines(p), 34 | file(f) 35 | {} 36 | std::set::iterator begin() 37 | { 38 | return lines->begin(); 39 | } 40 | std::set::iterator end() 41 | { 42 | return lines->end(); 43 | } 44 | std::shared_ptr> get_file() 45 | { 46 | return file; 47 | } 48 | private: 49 | std::string sought; 50 | std::shared_ptr> lines; 51 | std::shared_ptr> file; 52 | }; 53 | 54 | std::ostream& print(std::ostream&, const QueryResult&); 55 | 56 | class Query; 57 | 58 | class Query_base { 59 | friend class Query; 60 | protected: 61 | using line_no = TextQuery::line_no; 62 | virtual ~Query_base() = default; 63 | private: 64 | virtual QueryResult eval(const TextQuery &) const = 0; 65 | virtual std::string rep() const = 0; 66 | }; 67 | 68 | class Query { 69 | friend Query operator~(const Query &); 70 | friend Query operator|(const Query &, const Query &); 71 | friend Query operator&(const Query &, const Query &); 72 | public: 73 | Query(const std::string &); 74 | QueryResult eval(const TextQuery &t) const 75 | { 76 | return q->eval(t); 77 | } 78 | std::string rep() const { return q->rep(); } 79 | private: 80 | Query(std::shared_ptr query) : q(query) { } 81 | std::shared_ptr q; 82 | }; 83 | 84 | class WordQuery : public Query_base { 85 | friend class Query; 86 | WordQuery(const std::string &s) : query_word(s) { } 87 | QueryResult eval(const TextQuery &t) const 88 | { 89 | return t.query(query_word); 90 | } 91 | std::string rep() const 92 | { 93 | return query_word; 94 | } 95 | std::string query_word; 96 | }; 97 | 98 | class NotQuery : public Query_base { 99 | friend Query operator~(const Query &); 100 | NotQuery(const Query &q) : query(q) {} 101 | std::string rep() const override { 102 | return "~(" + query.rep() + ")"; 103 | } 104 | QueryResult eval(const TextQuery &) const override; 105 | Query query; 106 | }; 107 | 108 | class BinaryQuery : public Query_base { 109 | protected: 110 | BinaryQuery(const Query &l, const Query &r, std::string s) : 111 | lhs(l), rhs(r), opSym(s) { } 112 | std::string rep() const override { 113 | return "(" + lhs.rep() + " " + opSym + " " + rhs.rep() + ")"; 114 | } 115 | Query lhs, rhs; 116 | std::string opSym; 117 | }; 118 | 119 | class AndQuery : public BinaryQuery { 120 | friend Query operator& (const Query &, const Query &); 121 | AndQuery(const Query &left, const Query &right) : 122 | BinaryQuery(left, right, "&") {} 123 | QueryResult eval(const TextQuery &) const override; 124 | }; 125 | 126 | class OrQuery : public BinaryQuery { 127 | friend Query operator|(const Query &, const Query &); 128 | OrQuery(const Query &left, const Query &right) : 129 | BinaryQuery(left, right, "|") {} 130 | QueryResult eval(const TextQuery &) const override; 131 | }; 132 | 133 | inline 134 | Query::Query(const std::string &s) : q(new WordQuery(s)) { } 135 | 136 | inline Query 137 | operator~(const Query &rhs) 138 | { 139 | return std::shared_ptr(new NotQuery(rhs)); 140 | } 141 | 142 | inline Query 143 | operator&(const Query &lhs, const Query &rhs) 144 | { 145 | return std::shared_ptr(new AndQuery(lhs, rhs)); 146 | } 147 | 148 | inline Query 149 | operator|(const Query &lhs, const Query &rhs) 150 | { 151 | return std::shared_ptr(new OrQuery(lhs, rhs)); 152 | } 153 | 154 | inline std::ostream & 155 | operator<<(std::ostream &os, const Query &query) 156 | { 157 | return os << query.rep(); 158 | } 159 | 160 | #endif 161 | -------------------------------------------------------------------------------- /code/Disc_Quote.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | class Quote { 8 | public: 9 | Quote() = default; 10 | Quote(const std::string &book, double sales_price): 11 | bookNo(book), price(sales_price) { } 12 | std::string isbn() const { return bookNo; } 13 | virtual double net_price(std::size_t n) const 14 | { 15 | std::cout << "Quote::net_price" << std::endl; 16 | return n * price; 17 | } 18 | 19 | virtual Quote* clone() const & 20 | { 21 | return new Quote(*this); 22 | } 23 | virtual Quote* clone() && 24 | { 25 | return new Quote(std::move(*this)); 26 | } 27 | 28 | virtual ~Quote() = default; 29 | Quote(const Quote&) = default; 30 | Quote(Quote &&) = default; 31 | Quote& operator=(const Quote&) = default; 32 | Quote& operator=(Quote &&) = default; 33 | private: 34 | std::string bookNo; 35 | protected: 36 | double price = 0.0; 37 | }; 38 | 39 | class Disc_quote : public Quote { 40 | public: 41 | Disc_quote() = default; 42 | Disc_quote(const std::string &book, double price, std::size_t qty, double disc) 43 | : Quote(book, price), quantity(qty), discount(disc) { } 44 | double net_price(std::size_t n) const override = 0; 45 | std::pair discount_policy() const 46 | { return {quantity, discount}; } 47 | protected: 48 | std::size_t quantity = 0; 49 | double discount = 0.0; 50 | }; 51 | 52 | class Bulk_quote : public Disc_quote { 53 | public: 54 | using Disc_quote::Disc_quote; 55 | Bulk_quote() = default; 56 | double net_price(std::size_t count) const override; 57 | Bulk_quote* clone() const & 58 | { 59 | return new Bulk_quote(*this); 60 | } 61 | Bulk_quote* clone() && 62 | { 63 | return new Bulk_quote(std::move(*this)); 64 | } 65 | }; 66 | 67 | double 68 | Disc_quote::net_price(std::size_t count) const 69 | { 70 | return Quote::net_price(count); 71 | } 72 | 73 | double 74 | Bulk_quote::net_price(std::size_t count) const 75 | { 76 | std::cout << "Bulk_quote::net_price" << std::endl; 77 | if (count < quantity) { 78 | return Disc_quote::net_price(count); 79 | } else { 80 | return count * (1-discount) * price; 81 | } 82 | } 83 | 84 | class Basket { 85 | public: 86 | void add_item(const std::shared_ptr &sale) 87 | { 88 | items.insert(sale); 89 | } 90 | void add_item(const Quote &sale) 91 | { 92 | items.insert(std::shared_ptr(sale.clone())); 93 | } 94 | void add_item(Quote &&sale) 95 | { 96 | items.insert(std::shared_ptr(std::move(sale).clone())); 97 | } 98 | double total_receipt(std::ostream &) const; 99 | private: 100 | static bool compare(const std::shared_ptr &lhs, 101 | const std::shared_ptr &rhs) 102 | { 103 | return lhs->isbn() < rhs->isbn(); 104 | } 105 | std::multiset, decltype(compare)*> items{compare}; 106 | }; 107 | 108 | double 109 | print_total(std::ostream &os, const Quote &item, std::size_t n) 110 | { 111 | double ret = item.net_price(n); 112 | os << "ISBN: " << item.isbn() 113 | << " # sold: " << n << " total due: " << ret << std::endl; 114 | return ret; 115 | } 116 | 117 | double 118 | Basket::total_receipt(std::ostream &os) const 119 | { 120 | double sum = 0.0; 121 | for (auto iter = items.cbegin(); iter != items.cend(); iter = items.upper_bound(*iter)) 122 | { 123 | sum += print_total(os, **iter, items.count(*iter)); 124 | } 125 | os << "Total Sale: " << sum << std::endl; 126 | return sum; 127 | } 128 | 129 | int main() 130 | { 131 | //Disc_quote discounted; 132 | Bulk_quote bulk("XY-9889123", 14.5, 10, 0.19); 133 | Bulk_quote bulk2; 134 | Quote item("XY-9889123", 14.5); 135 | print_total(std::cout, bulk, 20); 136 | print_total(std::cout, item, 20); 137 | std::cout << bulk.isbn() << std::endl; 138 | 139 | std::vector basket; 140 | basket.push_back(Quote("0-201-82470-1", 50)); 141 | basket.push_back(Bulk_quote("0-201-54848-8", 50, 10, .25)); 142 | std::cout << basket.back().net_price(15) << std::endl; 143 | 144 | std::vector> basket2; 145 | basket2.push_back(std::make_shared("0-201-82470-1", 50)); 146 | basket2.push_back(std::make_shared("0-201-54848-8", 50, 10, .25)); 147 | std::cout << basket2.back()->net_price(15) << std::endl; 148 | return 0; 149 | } 150 | -------------------------------------------------------------------------------- /code/StrVec.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | class StrVec { 7 | public: 8 | StrVec(): 9 | elements(nullptr), 10 | first_free(nullptr), 11 | cap(nullptr) 12 | { } 13 | StrVec(const StrVec &); 14 | StrVec(StrVec &&) noexcept; 15 | StrVec& operator=(const StrVec &); 16 | StrVec& operator=(StrVec &&) noexcept; 17 | ~StrVec(); 18 | void push_back(const std::string &); 19 | void push_back(std::string &&); 20 | size_t size() const 21 | { 22 | return first_free - elements; 23 | } 24 | size_t capacity() const 25 | { 26 | return cap - elements; 27 | } 28 | std::string* begin() const { return elements; } 29 | std::string* end() const { return first_free; } 30 | 31 | StrVec & operator=(std::initializer_list); 32 | 33 | std::string & operator[](std::size_t n) 34 | { 35 | return elements[n]; 36 | } 37 | 38 | const std::string & operator[](std::size_t n) const 39 | { 40 | return elements[n]; 41 | } 42 | 43 | template 44 | void emplace_back(Args &&... args); 45 | private: 46 | void chk_n_alloc() 47 | { 48 | if (size() == capacity()) 49 | reallocate(); 50 | } 51 | std::pair 52 | alloc_n_copy(const std::string*, const std::string*); 53 | void free(); 54 | void reallocate(); 55 | private: 56 | std::allocator alloc; 57 | std::string *elements; 58 | std::string *first_free; 59 | std::string *cap; 60 | }; 61 | 62 | void StrVec::push_back(const std::string &s) 63 | { 64 | chk_n_alloc(); 65 | alloc.construct(first_free++, s); 66 | } 67 | 68 | void StrVec::push_back(std::string &&s) 69 | { 70 | chk_n_alloc(); 71 | //s 是左值,必须再次调用 std::move 72 | alloc.construct(first_free++, std::move(s)); 73 | } 74 | 75 | std::pair 76 | StrVec::alloc_n_copy(const std::string* b, const std::string* e) 77 | { 78 | std::string *data = alloc.allocate(e-b); 79 | return {data, std::uninitialized_copy(b, e, data)}; 80 | } 81 | 82 | void 83 | StrVec::free() 84 | { 85 | auto p = first_free; 86 | while (p != elements) { 87 | alloc.destroy(--p); 88 | } 89 | if (elements) { 90 | alloc.deallocate(elements, capacity()); 91 | } 92 | } 93 | 94 | StrVec::StrVec(const StrVec &sv) 95 | { 96 | auto newdata = alloc_n_copy(sv.begin(), sv.end()); 97 | elements = newdata.first; 98 | cap = first_free = newdata.second; 99 | } 100 | 101 | StrVec::StrVec(StrVec &&sv) noexcept 102 | : elements(sv.elements), 103 | first_free(sv.first_free), 104 | cap(sv.cap) 105 | { 106 | sv.elements = nullptr; 107 | sv.first_free = nullptr; 108 | sv.cap = nullptr; 109 | } 110 | 111 | StrVec& 112 | StrVec::operator=(const StrVec &rhs) 113 | { 114 | if (this == &rhs) 115 | return *this; 116 | auto newdata = alloc_n_copy(rhs.begin(), rhs.end()); 117 | free(); 118 | elements = newdata.first; 119 | cap = first_free = newdata.second; 120 | return *this; 121 | } 122 | 123 | StrVec& 124 | StrVec::operator=(StrVec &&rhs) noexcept 125 | { 126 | if (this == &rhs) 127 | return *this; 128 | free(); 129 | elements = rhs.elements; 130 | first_free = rhs.first_free; 131 | cap = rhs.cap; 132 | 133 | rhs.elements = nullptr; 134 | rhs.first_free = nullptr; 135 | rhs.cap = nullptr; 136 | return *this; 137 | } 138 | 139 | StrVec& StrVec::operator=(std::initializer_list il) 140 | { 141 | std::pair data = alloc_n_copy(il.begin(), il.end()); 142 | free(); 143 | elements = data.first; 144 | cap = first_free = data.second; 145 | return *this; 146 | } 147 | 148 | StrVec::~StrVec() 149 | { 150 | free(); 151 | } 152 | 153 | template 154 | inline void 155 | StrVec::emplace_back(Args&&... args) 156 | { 157 | chk_n_alloc(); 158 | alloc.construct(first_free++, std::forward(args)...); 159 | } 160 | 161 | void 162 | StrVec::reallocate() 163 | { 164 | auto newcapacity = size() ? size()*2 : 1; 165 | std::string *newdata = alloc.allocate(newcapacity); 166 | auto dest = newdata; 167 | auto elem = elements; 168 | auto last = uninitialized_copy(make_move_iterator(begin()), 169 | make_move_iterator(end()), 170 | newdata); 171 | //取消循环构建,改用迭代器 172 | /* 173 | while (elem != first_free) 174 | alloc.construct(dest++, std::move(*elem++)); 175 | */ 176 | free(); 177 | elements = newdata; 178 | first_free = last; 179 | cap = newdata + newcapacity; 180 | } 181 | 182 | int main() 183 | { 184 | StrVec svec; 185 | svec.push_back(""); 186 | svec.push_back("b"); 187 | const StrVec cvec = svec; 188 | if (svec.size() && svec[0].empty()) { 189 | svec[0] = "zero"; 190 | // error: cvec is constant, subscripting returns a const reference 191 | //cvec[0] = "Zip"; 192 | } 193 | std::cout << svec[0] << std::endl; 194 | return 0; 195 | } 196 | -------------------------------------------------------------------------------- /code/tuple.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | struct Sales_data { 11 | Sales_data() = default; 12 | Sales_data(const std::string isbn): Isbn(isbn), Cnt(0), Price(0.0) {} 13 | Sales_data(const std::string isbn, int cnt, double price) 14 | : Isbn(isbn), Cnt(cnt), Price(price) {} 15 | 16 | std::string Isbn; 17 | int Cnt = 0; 18 | double Price = 0.0; 19 | }; 20 | 21 | Sales_data operator+(const Sales_data &lhs, const Sales_data &rhs) { 22 | assert(lhs.Isbn == rhs.Isbn); 23 | double total_price = lhs.Cnt * lhs.Price + rhs.Cnt * rhs.Price; 24 | return Sales_data(lhs.Isbn, lhs.Cnt+rhs.Cnt, total_price/(lhs.Cnt+rhs.Cnt)); 25 | } 26 | 27 | std::ostream & operator<<(std::ostream &os, const Sales_data &o) { 28 | os << "Isbn: " << o.Isbn << " Cnt: " << o.Cnt << " Price: " << o.Price; 29 | return os; 30 | } 31 | 32 | typedef std::tuple::size_type, 33 | std::vector::const_iterator, 34 | std::vector::const_iterator> matches; 35 | 36 | struct Comp { 37 | bool operator()(const Sales_data &sd, const std::string &book) { 38 | return sd.Isbn < book; 39 | } 40 | bool operator()(const std::string &book, const Sales_data &sd) { 41 | return book < sd.Isbn; 42 | } 43 | }; 44 | 45 | std::vector 46 | findBook(const std::vector> &files, const std::string &book) 47 | { 48 | std::vector ret; 49 | for (auto it = files.cbegin(); it != files.cend(); ++it) 50 | { 51 | auto found = std::equal_range(it->cbegin(), it->cend(), book, Comp{}); 52 | if (found.first != found.second) { 53 | ret.push_back(std::make_tuple(it-files.cbegin(), found.first, found.second)); 54 | } 55 | } 56 | return ret; 57 | } 58 | 59 | void reportResults(const std::string &s, 60 | const std::vector> &files) 61 | { 62 | auto trans = findBook(files, s); 63 | if (trans.empty()) { 64 | std::cout << s << " not found in any stores" << std::endl; 65 | } 66 | for (const auto &store : trans) { 67 | std::cout << "store " << std::get<0>(store) << " sales: " 68 | << std::accumulate(std::get<1>(store), std::get<2>(store), Sales_data(s)) 69 | << std::endl; 70 | } 71 | } 72 | 73 | int main() 74 | { 75 | int i=1; 76 | std::tuple threeD{i,2,3}; 77 | std::cout << std::get<0>(threeD) << std::endl; 78 | std::cout << std::get<1>(threeD) << std::endl; 79 | std::cout << std::get<2>(threeD) << std::endl; 80 | 81 | typedef std::tuple, int, std::list> customTuple; 82 | customTuple someVal{"constants", {3.14, 2.718}, 42, {0,1,2,3,4,5}}; 83 | 84 | std::tuple_element<0, customTuple>::type str = "customTuple"; 85 | std::cout << std::tuple_size::value << std::endl; 86 | 87 | // the two string is different 88 | std::string str2{10, 'c'}; //"\nc" 89 | std::string str3(10, 'c'); 90 | std::cout << "str2:" << str2 << std::endl; 91 | std::cout << "str3:" << str3 << std::endl; 92 | 93 | //item's type is `std::tuple` 94 | auto item = std::make_tuple("0-999-78345-X", 3, 20.00); 95 | auto book = std::get<0>(item); 96 | auto cnt = std::get<1>(item); 97 | auto price = std::get<2>(item)/cnt; 98 | std::get<2>(item) *= 0.8; 99 | std::cout << std::get<2>(item) << std::endl; 100 | 101 | typedef decltype(item) trans; 102 | size_t sz = std::tuple_size::value; 103 | std::tuple_element<1, trans>::type cnt2 = std::get<1>(item); 104 | 105 | //equality and relational operations 106 | std::tuple duo("1", "2"); 107 | std::tuple twoD(1, 2); 108 | //bool b = (duo == twoD); //错误:不能将 size_t 和 string 进行比较 109 | std::tuple threeD2(1,2,3); 110 | //bool b = (twoD < threeD2); //可以编译但行为不对 111 | //std::cout << "b is: " << b << std::endl; 112 | 113 | std::tuple origin(0, 0); 114 | bool b1 = (origin < twoD); 115 | std::cout << "b1 is: " << b1 << std::endl; 116 | 117 | std::vector> files = { 118 | { {"799-9999", 12, 9}, {"899-9999", 12, 9}, {"899-9999", 12, 10}, {"999-9999", 12, 9} }, 119 | { {"799-9999", 12, 9}, {"999-9999", 12, 11}, {"999-9999", 12, 9} }, 120 | { {"799-9999", 12, 9}, {"799-9999", 12, 9}, {"899-9999", 12, 12}, {"999-9999", 12, 9} }, 121 | }; 122 | 123 | std::vector storeMatches = findBook(files, "899-9999"); 124 | for (auto it = storeMatches.cbegin(); it != storeMatches.cend(); ++it) { 125 | std::cout << "indice: " << std::get<0>(*it) << std::endl; 126 | for (auto start = std::get<1>(*it), end = std::get<2>(*it); start != end; ++start) 127 | { 128 | std::cout << "price is " << start->Price << std::endl; 129 | } 130 | } 131 | reportResults("899-9999", files); 132 | 133 | return 0; 134 | } 135 | -------------------------------------------------------------------------------- /code/template.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | template 9 | T foo(T* p) 10 | { 11 | T tmp = *p; 12 | return tmp; 13 | } 14 | 15 | template 16 | T calc(const T &, const U &) 17 | { 18 | } 19 | 20 | template 21 | int compare(const char (&p1)[N], const char (&p2)[M]) 22 | { 23 | std::cout << "compare char array reference" << std::endl; 24 | std::cout << N << std::endl; 25 | std::cout << M << std::endl; 26 | return strcmp(p1, p2); 27 | } 28 | 29 | template 30 | inline T min(const T &a, const T &b) 31 | { 32 | if (a < b) 33 | return a; 34 | else 35 | return b; 36 | } 37 | 38 | template 39 | int compare(const T &v1, const T &v2) 40 | { 41 | if (std::less()(v1, v2)) return -1; 42 | if (std::less()(v2, v1)) return 1; 43 | return 0; 44 | } 45 | 46 | // Function template specialization does not affect function matching. 47 | // 48 | // It must specialize all template parameters. 49 | // 50 | // If we comment next line, it will be a nontemplate function which affects 51 | // function matching subtly. 52 | // 53 | // When a nontemplate function provides an equally good match as a function 54 | // template, the nontemplate function is selected. 55 | template <> 56 | int compare(const char* const &v1, const char* const &v2) 57 | { 58 | std::cout << "compare reference to a const pointer to const char" << std::endl; 59 | return strcmp(v1, v2); 60 | } 61 | 62 | // compare2 can apply to every lvalue (include const lvalue), 63 | // but cann't apply to rvalue 64 | template 65 | int compare2(T &v1, T &v2) 66 | { 67 | if (std::less()(v1, v2)) return -1; 68 | if (std::less()(v2, v1)) return 1; 69 | return 0; 70 | } 71 | 72 | ////////////////////////////////////////////////////////// 73 | template 74 | class Pal; 75 | 76 | class C { 77 | friend class Pal; 78 | //All instances of Pal2 are friends to C 79 | //no forward declaration required 80 | template friend class Pal2; 81 | }; 82 | 83 | template 84 | class C2 { 85 | friend class Pal; 86 | //All instances of Pal2 are friends to C2 87 | //The friend declaration must use different parameters 88 | template friend class Pal2; 89 | 90 | friend class Pal3; 91 | }; 92 | 93 | template 94 | class Bar { 95 | //Under the new standard, make a template type parameter a friend 96 | friend Type; 97 | }; 98 | 99 | /////////////////////////////////////////////////////////////////////// 100 | template 101 | T1 sum(const T2 &lhs, const T3 &rhs) 102 | { 103 | return lhs + rhs; 104 | } 105 | 106 | //////////////////////////////////////////////////////////////////// 107 | 108 | template 109 | auto fcn(It beg, It end) -> decltype(*beg) 110 | { 111 | return *beg; 112 | } 113 | 114 | template 115 | auto fcn2(It beg, It end) -> typename std::remove_reference::type 116 | { 117 | return *beg; 118 | } 119 | 120 | void func(int (*)(const std::string &, const std::string &)); 121 | void func(int (*)(const int &, const int &)); 122 | 123 | template void f3(T &&x) 124 | { 125 | std::cout << "f " << x << std::endl; 126 | } 127 | // void f3(int& &&); 128 | 129 | template void g(const T &&x) 130 | { 131 | std::cout << "g " << x << std::endl; 132 | } 133 | 134 | //////////////////////////////////////////////////////////// 135 | 136 | template 137 | std::string debug_rep(const T &t) 138 | { 139 | std::ostringstream ret; 140 | ret << t; 141 | return ret.str(); 142 | } 143 | 144 | template 145 | std::string debug_rep(T *p) 146 | { 147 | std::ostringstream ret; 148 | ret << "pointer: " << p; 149 | if (p) 150 | ret << " " << debug_rep(*p); 151 | else 152 | ret << " null pointer"; 153 | return ret.str(); 154 | } 155 | 156 | int main() 157 | { 158 | compare("hi", "mom"); 159 | const char *p1 = "hi", *p2 = "mom"; 160 | compare(p1, p2); 161 | 162 | long lng = 1024; 163 | compare(lng, 1024); 164 | compare(lng, 1024); 165 | 166 | const long clng1 = 1024; 167 | const long clng2 = 2048; 168 | std::cout << compare2(clng1, clng2) << std::endl; 169 | 170 | Bar b; 171 | long long val3 = sum(1, 2); 172 | 173 | std::vector vi = {1,2,3,4,5}; 174 | auto &i = fcn(vi.begin(), vi.end()); 175 | 176 | int (*pf1)(const int &, const int &) = compare; 177 | 178 | //Disambiguate the call to func by using explicit template arguments 179 | //func(compare); 180 | //func(compare); 181 | 182 | int x = 100; 183 | f3(x); 184 | //g(x); 185 | g(100); 186 | 187 | std::string s("hi"); 188 | std::cout << debug_rep(s) << std::endl; 189 | std::cout << debug_rep(&s) << std::endl; 190 | 191 | const std::string *sp = &s; 192 | std::cout << debug_rep(sp) << std::endl; 193 | 194 | return 0; 195 | } 196 | -------------------------------------------------------------------------------- /code/StrBlob.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | class StrBlobPtr; 9 | 10 | class StrBlob { 11 | friend class StrBlobPtr; 12 | public: 13 | typedef std::vector::size_type size_type; 14 | StrBlob(); 15 | StrBlob(std::initializer_list il); 16 | 17 | size_type size() const; 18 | bool empty() const; 19 | void push_back(const std::string &t); 20 | void pop_back(); 21 | std::string& front(); 22 | const std::string& front() const; 23 | std::string& back(); 24 | const std::string& back() const; 25 | 26 | StrBlobPtr begin(); 27 | StrBlobPtr end(); 28 | private: 29 | std::shared_ptr> data; 30 | void check(size_type i, const std::string &msg) const; 31 | }; 32 | 33 | ////////////////////////////////////////////////////////////////////// 34 | 35 | class StrBlobPtr { 36 | public: 37 | StrBlobPtr(): wptr(), curr(0){ } 38 | StrBlobPtr(StrBlob &a, StrBlob::size_type sz = 0): wptr(a.data), curr(sz) { } 39 | std::string& deref() const; 40 | StrBlobPtr& incr(); 41 | 42 | StrBlobPtr& operator++(); 43 | StrBlobPtr operator++(int); 44 | StrBlobPtr& operator--(); 45 | StrBlobPtr operator--(int); 46 | std::string & operator*() const 47 | { 48 | auto p = check(curr, "dereference past end"); 49 | return (*p)[curr]; 50 | } 51 | std::string * operator->() const 52 | { 53 | return & this->operator*(); 54 | } 55 | private: 56 | std::shared_ptr> 57 | check(std::size_t, const std::string &) const; 58 | private: 59 | std::weak_ptr> wptr; 60 | StrBlob::size_type curr; 61 | }; 62 | 63 | /////////////////////////////////////////////////////////////////////// 64 | 65 | StrBlob::StrBlob(): 66 | data(std::make_shared>()) 67 | { 68 | } 69 | 70 | StrBlob::StrBlob(std::initializer_list il): 71 | data(std::make_shared>(il)) 72 | {} 73 | 74 | inline StrBlob::size_type 75 | StrBlob::size() const 76 | { 77 | return data->size(); 78 | } 79 | 80 | inline bool 81 | StrBlob::empty() const 82 | { 83 | return data->empty(); 84 | } 85 | 86 | inline void 87 | StrBlob::push_back(const std::string &t) 88 | { 89 | data->push_back(t); 90 | } 91 | 92 | void 93 | StrBlob::check(size_type i, const std::string &msg) const 94 | { 95 | if (i >= data->size()) 96 | throw std::out_of_range(msg); 97 | } 98 | 99 | void 100 | StrBlob::pop_back() 101 | { 102 | check(0, "pop_back on empty StrBlob"); 103 | data->pop_back(); 104 | } 105 | 106 | std::string& 107 | StrBlob::front() 108 | { 109 | check(0, "front on empty StrBlob"); 110 | return data->front(); 111 | } 112 | 113 | const std::string& 114 | StrBlob::front() const 115 | { 116 | check(0, "front on empty StrBlob"); 117 | return data->front(); 118 | } 119 | 120 | std::string& 121 | StrBlob::back() 122 | { 123 | check(0, "back on empty StrBlob"); 124 | return data->back(); 125 | } 126 | 127 | const std::string& 128 | StrBlob::back() const 129 | { 130 | check(0, "back on empty StrBlob"); 131 | return data->back(); 132 | } 133 | 134 | StrBlobPtr 135 | StrBlob::begin() 136 | { 137 | return StrBlobPtr(*this); 138 | } 139 | 140 | StrBlobPtr 141 | StrBlob::end() 142 | { 143 | return StrBlobPtr(*this, data->size()); 144 | } 145 | 146 | ///////////////////////////////////////////////////////////////// 147 | 148 | std::shared_ptr> 149 | StrBlobPtr::check(std::size_t i, const std::string &msg) const 150 | { 151 | auto ret = wptr.lock(); 152 | if (!ret) 153 | throw std::runtime_error("unbound StrBlobPtr"); 154 | if (i >= ret->size()) 155 | throw std::out_of_range(msg); 156 | return ret; 157 | } 158 | 159 | std::string& 160 | StrBlobPtr::deref() const 161 | { 162 | auto p = check(curr, "dereference past end"); 163 | return p->operator[](curr); 164 | } 165 | 166 | StrBlobPtr& 167 | StrBlobPtr::incr() 168 | { 169 | check(curr, "increment past end of StrBlobPtr"); 170 | ++curr; 171 | return *this; 172 | } 173 | 174 | StrBlobPtr& StrBlobPtr::operator++() 175 | { 176 | check(curr, "increment past end of StrBlobPtr"); 177 | ++curr; 178 | return *this; 179 | } 180 | 181 | StrBlobPtr StrBlobPtr::operator++(int) 182 | { 183 | StrBlobPtr ret = *this; 184 | ++*this; 185 | return ret; 186 | } 187 | 188 | StrBlobPtr& StrBlobPtr::operator--() 189 | { 190 | --curr; 191 | check(curr, "decrement past begin of StrBlobPtr"); 192 | return *this; 193 | } 194 | 195 | StrBlobPtr StrBlobPtr::operator--(int) 196 | { 197 | StrBlobPtr ret = *this; 198 | --*this; 199 | return ret; 200 | } 201 | 202 | int main() 203 | { 204 | StrBlob sb1{"1","2","3","4"}; 205 | StrBlob sb2 = sb1; //此时两个对象共享相同的 vector 206 | 207 | StrBlobPtr p(sb1); 208 | std::cout << p.operator++(0).deref() << std::endl; 209 | std::cout << p.operator++().deref() << std::endl; 210 | 211 | StrBlob al = { "hi", "bye", "now" }; 212 | StrBlobPtr p2(al); 213 | *p = "okay"; 214 | std::cout << p->size() << std::endl; 215 | std::cout << (*p).size() << std::endl; 216 | 217 | return 0; 218 | } 219 | --------------------------------------------------------------------------------