• 范文大全
  • 公文写作
  • 工作总结
  • 工作报告
  • 医院总结
  • 合同范文
  • 党团范文
  • 心得体会
  • 讲话稿
  • 安全管理
  • 广播稿
  • 条据书信
  • 优秀作文
  • 口号大全
  • 简历范文
  • 应急预案
  • 经典范文
  • 入党志愿书
  • 感恩演讲
  • 发言稿
  • 工作计划
  • 党建材料
  • 脱贫攻坚
  • 党课下载
  • 民主生活会
  • 不忘初心
  • 主题教育
  • 对照材料
  • 您现在的位置:雨月范文网 > 入党志愿书 > 正文

    个人笔记总结

    来源:雨月范文网 时间:2020-08-28 点击:

     C++ 个人笔记总结

     ---------------------------------

     ---------------

     Good luck

     Believe yourself

      Just go

      - 1 -

      概述:

     一、 C++ 语言语法基础 (6)

     1.从 C 到 C++的过渡 2.类和对象 3.操作符重载 4.继承与多态 5.异常和 I/O 流

     二、数据结构和算法

     1.基本数据结构,堆栈、队列、链表、二叉树,实现和应用(2) 2.排序和查找算法

     三、模板和 STL

     1.模板语法 2.STL

      四、阶段项目

     简化的企业管理信息系统(MIS)

      - 2 - 第一课

     从 从 C C 到 到 C++ 的过渡

     一、背景介绍

     算盘 - 面向硬件的编程 电子计算机 - 机器语言的编程 1010

     - 汇编语言的编程 ADD

     - 高级语言的编程 Fortran

     printf ("%d", 12);

     - 结构化程序设计 C/PASCL

     顺序、分支、循环、函数

     - 面向对象的程序设计 C++/Java/C#

     - 面向问题的程序设计 1960 - Algol 60,算法语言,远离硬件,不适合进行系统开发 1963 - 剑桥大学,CPL,在 Algol 60 的基础上增加对系统开发的支

     持,复杂,不易掌握,不易使用 1970 - MIT,BCPL,CPL 的精华版,易学易用,太慢,不实用 1972 - Ken Thomposon,B 语言,通过运行时支持优化 BCPL 的性能,缺少类型 1973 - Dennis Ritchie,C 语言,用 C 重新实现 UNIX 内核 1978 - 《The C Programming Language》,第一个 C 语言的事实标准 1989 - ANSI C,C89 1990 - ISO C, C90 1999 - ISO C 修订,C99 197X - Bajarne Stroustrup,simula 早期的面向对象语言,性能低

     下,B 语言。

     1979 - 贝尔实验室,多核 UNIX 系统仿真,Cpre, 通过扩展宏为 C 语言增加类似 simula 的面向对象机制。C with Class: simula - 类 Alogo 68 - 操作符重载 Ada - 模板、名字空间 Smalltalk - 引用、异常 C 是 C++的子集,C++是对 C 的扩展。

     1983 - C++命名 1985 - CFront 1.0,第一款商用 C++编译器 1987 - GNU C++ 1990 - Borland C++ 1992 - Microsoft C++,IBM C++ 1998 - ISO C++98 2003 - ISO C++03 2011 - ISO C++2011/C++11/C++0x

      - 3 - 二、 C++ 语言的使用领域:

     1.游戏开发:强建模能力,性能高。

     2.科学计算:FORTRAN,C++算法库。

     3.网络和分布式:ACE 框架。

     4.桌面应用:VC/MFC,Office,QQ,多媒体 5.操作系统和设备驱动:优化编译器的发明使 C++在底层开发方面可

      以和 C 向媲美。

     6.移动终端

      既需要性能,同时又要有面向对象的建模。

      三、 C++比 比 C C 更丰富

     1.支持面向对象,将问题域和方法域统一化。宏观面向对象,微观面

      向过程。

     2.支持泛型编程。

     int add (int a, int b) { ... } template<typename T> T add (T a, T b) { ... } 3.支持异常机制。

     int func (void) {

      ... } int main (void) {

      if (func () == -1) {

     错误处理;

      } } 4.操作符重载

     四、第一个 C++ 程序

     1.编译器:g++,如果用 gcc 需要带上-lstdc++, 指定其使用标准 c++的运行库。

     2.源文件扩展名:.cpp/.cc/.C/.cxx/.c++,最好用.cpp

     3.头文件:#include <iostream>

      大多数标准库头文件都没有.h 后缀。

     4.输出:cout - 标准输出对象

      输入:cin

     - 标准输入对象

      插入运算符:<<

      提取运算符:>> 5.std:所有标准库的函数、对象、类型都位于 std 名字空间中。

      - 4 - 五、名字空间

     1. 对程序中的标识符(类型、函数、变量), ,

     按照某种逻辑规则划分成若干组。

      2. 定义名字空间

     namespace 名字空间名 {

      名字空间成员; }

     3. 使用名字空间

     1 1 作用于限定符:名字空间名 :: 名字空间成员,

     表示访问特定名字空间中的特定成员。

     例子:

     #include <iostream> int main (void) {

     std ::cout << "Hello, World !" << std ::endl;

     int i;

     double d;

     char s[256];

     //

     scanf ("%d%lf%s", &i, &d, s);

     std ::cin >> i >> d >> s;

      //

     printf ("%d %lf %s\ \ n", i, d, s);

      std ::cout << i << " " << d << " " << s << "\n";

     return 0; } ---------------------------------------------------------

     2 2 名字空间指令:

     using namespace 名字空间名; 在该条指令之后的代码对指令所指名字空间中的所有成员都可见, 可直接访问这些成员,无需加“::”。

     例:

     using namespace std;

     3 3 名字空间声明:

     using 名字空间名::名字空间成员; 将指定名字空间中的某个成员引入当前作用域, 可直接访问这些成员,无需加“::”。

      - 5 - 4. 匿名名字空间

     如果一个标识符没有被显示地定义在任何名字空间中, 编译器会将其缺省地置于匿名名字空间中。

     对匿名名字空间中的成员通过“::名字空间成员”的形式访问。

     5. 名字空间合并

     6. 名字空间嵌套

     namespace ns1 {

      namespace ns2 {

      namespace ns3 {

      void foo (void) { ... }

      }

      } } ns1::ns2::ns3::foo (); using namespace ns1::ns2::ns3; foo (); ---------------

     例子:名字空间

     #include <iostream> using namespace std; //namespace {

     void print (int money) {

      cout << money << endl;

     } //} // 农行名字空间

     namespace abc {

     int balance = 0;

     void save (int money) {

      balance += money;

     }

     void draw (int money) {

      balance -= money;

     } } namespace abc {

     void salary (int money) {

      balance += money;

     }

      - 6 -

     void print (int money) {

      cout << "农行:";

      ::print (money);

     } } // 建行名字空间

     namespace ccb {

     int balance = 0;

     void save (int money) {

      balance += money;

     }

     void draw (int money) {

      balance -= money;

     }

     void salary (int money) {

      balance += money;

     } } int main (void) {

     using namespace abc; // 名字空间指令

     save (5000);

     cout << "农行:" << balance << endl;

      draw (3000);

     cout << "农行:" << balance << endl;

     ccb::save (8000);

     cout << "建行:" << ccb::balance << endl;

     ccb::draw (5000);

     cout << "建行:" << ccb::balance << endl;

     using ccb::salary; //

     名字空间声明 // using abc::salary;

     salary (6000);

     cout << "建行:" << ccb::balance << endl;

     abc::print (abc::balance);

     return 0; }

      - 7 - 六、 C++ 中的结构、联合和枚举

      1. 结构

      和 C 语言的不同:

     1)定义结构型变量时,可以省略 struct 关键字。

     2)结构内部可以定义函数——成员函数。

     3)sizeof (空结构) -> 1

      例子:

     #include <iostream> using namespace std; struct Student {

     char name[128];

     int age;

     void who (void) {

      // 成员函数

      cout << "我叫" << name << ",今年" << age

     << "岁了。" << endl;

     } }; int main (void) {

     Student student = {"张飞", 25}, *ps = &student;

     student.who ();

     ps->who ();

     struct A {};

     cout << sizeof (A) << endl;

     return 0; } ----------------------------------------------------------- 2. 联合

     增加了匿名联合的概念。借用联合语法形式, 描述一些变量在内存中的布局方式。

     int main() {

     UNION

      {

      int a;

      char ch[4];

     };

      a=0x12345678; } 定义联合变量时,可以不加 union

      - 8 - 例子:

     #include <iostream> using namespace std; int main (void) {

     // 匿名联合

     union {

      int x;

      char c[4] /*= {"A", "B", "C", "D"}*/;

     };

     cout << (void*)&x << " " << (void*)c << endl;

     x = 0x12345678;

     for (int i = 0; i < 4; ++i)

      cout << hex << (int)c[i] << " ";

     cout << endl;

     return 0; }

      ---------------------------------------------------

     3. 枚举

     枚举是一个独立的数据类型。

     C: enum E {a, b, c}; enum E e; e = a; e = 1000; C++: enum E {a, b, c}; E e; e = a; e = b; e = c; b=1;

      // ERROR !

     e = 1000; // ERROR !

     e = 1;

     // ERROR !

      - 9 - 例子:

     #include <iostream> using namespace std; int main (void) {

     enum E {a, b, c};

     E e;

     e = a;

     e = b;

     e = c;

     / // / e = 1000; // 报错

      // e = 1;

      // 报错

      return 0;}

     七、 C++ 的布尔类型,跟在 t cout 后面可以 boolalpha

     bool b = true; b = false; cout << sizeof (b) << endl; // 1 b = 100; b = 1.234; b = "hello"; b = "A"; 八、 C++ 中的运算符别名

     && - and || - or &

     - bitand

     ^

     - xor {

     - <%

      }

     - %> [

     - <: ]

     - :>

      - 10 - 九、 C++ 中的函数

     1. 重载:条件

      在同一个作用域中,

     函数名相同,

     参数表不同的函数,

     构成重载关系。

     C++编译器会对程序中的函数做换名, 将参数表中的类型信息汇合到函数名中,以保证函数名的唯一。

     通过 extern "C",可以要求编译器不做 C++换名,以方便在 C 语言的模块中使用C++编译生成的代码。

     方式一:

     extern "C" {

     int add (int a, int b) {

     return a + b;

     } }

     int sub (int a, in t b) {

     return a - -

     b;

     } }

     } }

     方式二:

     extern "C" int add (int a, int b, int c) {

     return a + b + c;

     } } 2. 缺省参数和哑元参数

     1)如果调用一个函数时,没有提供实参,那么对应形参就取缺省值。

     2)如果一个参数带有缺省值,那么 它后边的所有参数必须都带有缺省值。

     3)如果一个函数声明和定义 分开,那么缺省参数 只能放在声明中。

     4)避免和重载发生歧义。

     5)只有类型而没有名字的形参,谓之哑元。

     i++ - operator++ ++i V1: void decode (int arg) { ... } V2: void decode (int) { ... } 例子 1 1 :重载与缺省值

     #include <iostream> using namespace std; void foo (int a = 10, double b = 0.01,

     const char* c = "tarena");

      // 函数 1 1

     void foo (void) {}

      // 函数 2 2 // 函数 1 1 与函数 2 2 构成重载关系

     void bar (int) {

     // 函数 3 3

      - 11 -

     cout << "bar(int)" << endl; } void bar (int, double) {

     // 函数 4 4

      cout << "bar(int,double)" << endl; } // 函数 3 3 与函数 4 4 构成重载关系

     int main (void) {

     foo (1, 3.14, "hello"); // 调用函数 1 1

     foo (1, 3.14);

      // 调用函数 1 1

      foo (1);

      // 调用函数 1

     //

     foo (); // 歧义

     ,可以调用函数 2 2 ,但也可以调用函数 1 1 ,因为函数 1 1 在不提供实参的情况下, 可以取缺省值。

      bar (100);

      // 调用函数 3 3

     bar (100, 12.34);

     // 调用函数 4 4

     return 0; } --------------------------------------

     例子 2 2 :重载与作用域

     #include <iostream> using namespace std; namespace ns1 {

     int foo (int a) {

      函数 1 1

     cout << "ns1::foo(int)" << endl;

      return a;

     } }; namespace ns2 {

     double foo (double a) {

      函数 2 2

     cout << "ns2::foo(double)" << endl;

      return a;

     } }; int main (void) {

     using namespace ns1;

     // 名字空间指令

     using namespace ns2;

     // 名字空间指令

     cout << foo (10) << endl;

     //10 调用函数 1 1 ,作用域可见 2 ns2 与 与 ns1 ,所以与函数 2 2构成重载

      cout << foo (1.23) << endl;

     //1.23 调用函数 2 2 ,作用域可见 2 ns2 与 与 ns1 ,所以与函数1 1 构成重载

      - 12 -

      using ns1::foo;

     // 名字空间声明 (当同时出现名字指令与名字空间声明,则名字空间声明会隐藏名字空间指令)

      cout << foo (10) << endl;

     //10 ,调用函数 1 1 ,只可见名字空间 1 ns1 的 的 foo(), 所以也并不构成重载。

      cout << foo (1.23) << endl;

     //10 ,调用函数 1 1 ,只可见名字空间 1 ns1 的 的 foo(), 所以也并不构成重载。

     using ns2::foo;

     // 名字空间声明

     cout << foo (10) << endl;

     //10 ,调用函数 1 1 ,可见名字空间 1 ns1 与名字空间 2 ns2 的foo(), 所以构成重载。

     cout << foo (1.23) << endl;

     //1.23 ,调用函数 2 2 ,可见名字空间 1 ns1 与名字空间 2 ns2 的foo(), 所以构成重载。

     return 0; } --------------------------------------------------------

     3. 内联

     1)编译器用函数的二进制代码替换函数调用语句,减少函数调用的时间开销。这种优化策略成为内联。

     2)频繁调用的简单函数适合内联,而稀少调用的复杂函数不适合内联。

     3) 递归函数无法内联。

     4)通过 inline 关键字,可以建议编译对指定函数进行内联,但是仅仅是建议而已。

      inline void foo (int x, int y){...}

      - 13 - 十、 C++ 的动态内存分配

     malloc/calloc/realloc/free 1.new/delete:对单个变量进行内存分配/释放 2.new[]/delete[]:对数组进行内存分配/释放 例子:w new 与 与 delete

     #include <iostream> using namespace std; int main (void) {

      // int* pi = (int*)malloc (sizeof (int));

      // free (pi);

     c //c 中的方法

     int* pi = new int;

     *pi = 1000;

     cout << *pi << endl;

     delete pi;

      // 一定要释放内存,否则会造成内存泄露,很严重

      pi = NULL;

      // 不要忘记这个,虽然不会 报错,但是要有好习惯

      /*

      *pi = 2000;

     cout << *pi << endl;

      i //pi 指向的内存地址已经被释放,被初始化为指向 NULL

     */

     pi = new int[10];

     for (size_t i = 0; i < 10; ++i)

      pi[i] = i;

     for (size_t i = 0; i < 10; ++i)

      cout << pi[i] << " ";

     cout << endl;

     delete[] pi;

     // 千 万记住 new[] 要用 delete[] 来释放内存

      pi = NULL;

     pi = new int (1234);

      //用 用 w new 分配内存的同时初始化赋一个值。

      cout << *pi << endl;

     //1234

     delete pi;

     pi = NULL;

     char buf[4] = {0x12,0x34,0x56,0x78};

     pi = new (buf) int;

     cout << hex << *pi << endl; //

     delete pi;

      cout << (void*)pi << " " << (void*)buf << endl;

     int (*p)[4] = new int[3][4];

     delete[] p;

     int (*q)[4][5] = new int[3][4][5];

     delete[] q;

     return 0; }

      - 14 - 十一、引用

     1. 引用即别名。

     int a = 20; int& b = a; // int* b = &a; b = 10; // *b = 10; cout << a << endl; // 10 2. 引用必须初始化。

     int a; int* p; a = 20; p = &a; int& b; // ERROR ! int& b = a; // OK 3. 引用一旦初始化就不能再引用其它变量。

     int a = 20, c = 30; int& b = a; b = c; // c => b/a 4. 引用的应用场景

     1) 引用型参数

     a.修改实参 b.避免拷贝,通过加 const 可以防止在函数中意外地修改实参的值,同时还可以接受拥有常属性的实参。

     2) 引用型返回值

     int b = 10; int a = func (b); func (b) = a; 从一个函数中返回引用往往是为了将该函数的返回值作为左值使用。但是,一定要保证函数所返回的引用的目标在该函数返回以后依然有定义,否则将导致不确定的后果。

     不要返回局部变量的引用,可以返回全局、静态、成员变量的引用,也可以返回引用型形参变量本身。

      5. 引用和指针

     1)引用的本质就是指针,很多场合下引用和指针可以互换。

     2)在 C++层面上引用和指针存在以下不同:

      - 15 - A. 指针式实体变量,但是引用不是实体变量。

     int& a = b; sizeof (a); // 4 double& d = f; sizeof (d); // 8 B. 指针可以不初始化,但是引用必须初始化。

     C. 指针的目标可以修改,但是引用的目标的不能修改。

     D. 可以定义指针的指针,但是不能定义引用的指针。

     int a; int* p = &a; int** pp = &p;

     // OK int& r = a; int&* pr = &r;

     // ERROR E. 可以定义指针的引用,但是不能定义引用的引用。

     int a; int* p = &a; int*& q = p;

     // OK int& r = a; int&& s = r; // ERROR F. 可以定义指针的数组,但是不能定义引用的数组。

     int a, b, c; int* parr[] = {&a, &b, &c}; // OK

     int& rarr[] = {a, b, c};

     // ERROR 可以定义数组的引用。

     int arr[] = {1, 2, 3}; int (&arr_ref)[3] = arr;

     // OK 例子:指针与引用

     #include <iostream> using namespace std; void swap1 (int a, int b) {

     int c = a;

     a = b;

     b = c; } void swap2 (int* a, int* b) {

     int c = *a;

     *a = *b;

     *b = c; } void swap3 (int& a, int& b) {

     int c = a;

     a = b;

     b = c;

      - 16 - } void swap4 (const char* x, const char* y) {

     const char* z = x;

     x = y;

     y = z; } void swap5 (const char** x, const char** y) {

     const char* z = *x;

     *x = *y;

     *y = z; } void swap6 (const char*& x, const char*& y) {

     const char* z = x;

     x = y;

     y = z; } struct Student {

     char name[1024];

     int age; }; void print (const struct Student& s) {

     cout << s.name << "," << s.age << endl; // s.age = -1; } void foo (const int& x) {

     cout << x << endl; } int main (void) {

     int a = 100, b = 200; // swap1 (a, b); // swap2 (&a, &b);

     swap3 (a, b);

     cout << a << " " << b << endl; // 200 100

     const char* x = "hello", *y = "world"; // swap4 (x, y); // swap5 (&x, &y);

     swap6 (x, y);

     cout << x << " " << y << endl;

     Student s = {"张飞", 22};

     print (s);

     print (s);

     foo (100);

     return 0; }

      - 17 - 十二、显示类型转换运算符

     C:目标类型变量 = (目标类型)源类型变量; 1. 静态类型转换

     static_cast<目标类型> (源类型变量) 如果在目标类型和源类型之间某一个方向上可以做隐式类型转换,那么在两个方向上都可以做静态类型转换。反之如果在两个方向上都不能做隐式类型转换,那么在任意一个方向上也不能做静态类型转换。

     int* p1 = ...; void* p2 = p1; p1 = static_cast<int*> (p2); char c; int i = c; 如果存在从源类型到目标类型的自定义转换规则,那么也可以使用静态类型转换。

     例子:静态类型转换

     #include <iostream> using namespace std; int main (void) {

     int* p1 = NULL;

      1 //p1 为 为 t int 型的指针

      void* p2 = p1;

     2 //p2 为 为 d void 型的指针

     p1 = static_cast<int*> (p2);

      //将 将 d void 型的 2 p2 指针转换为 t int 型指针并复制给 int型的 1 p1 指针。

      return 0; } --------------------------------------------------- 2. 动态类型转换

     dynamic_cast<目标类型> (源类型变量) 用在具有多态性的父子类指针或引用之间。

     3. 常类型转换

     const_cast<目标类型> (源类型变量) 给一个拥有 const 属性的指针或引用去常 const int a = 100; const int* p1 = &a; *p1 = 200; // ERROR int* p2 = const_cast<int*> (p1); *p2 = 200; // OK 4. 从解释类型转换

     reinterpret_cast<目标类型> (源类型变量); 在不同类型的指针或引用之间做类型转换,以及在指针和整型之间做类型转换。

     5. 目标类型变量

     = 目标类型( ( 源类型变量) ) ;

     int a = int (3.14);

      - 18 - 例子一:常类型转换

     #include <iostream> using namespace std; int main (void) {

     const volatile int a = 100; ( (字 关键字 e volatile 在描述变量时使用, ,以 阻止编译器优化那些以 e valatile 修饰的变量 ,volatile被用在一些变量能被意外方式改变的地方, , 例如: : 抛出中断, , 这些变量若无 volate ile 可能会和编译器执行的优化

     相冲突. .) )

     //

     a = 200;

      const volatile int* p1 = &a; //

     *p1 = 200;

     int* p2 = const_cast<int*> (p1); / // / 去常,去掉常属性

     *p2 = 200;

     cout << *p2 << endl;

     // 200

      cout << a << endl;

      // 200

     // cout << 100 << endl;

      return 0;

     } -------------------- -----------------------------------

     例子二:解释型类型转换

     #include <iostream> using namespace std; int main (void) {

     int i = 0x12345678;

     char* p = reinterpret_cast<char*> (&i);

     for (size_t i = 0; i < 4; ++i)

      cout << hex << (int)p[i] << " ";

     //78 56 34 12

      cout << endl;

     float* q = reinterpret_cast<float*> (&i);

     cout << *q << endl;

     void* v = reinterpret_cast<void*> (i);

     cout << v << endl;

     return 0; }

      - 19 - 十三、 C++ 之父的建议

     1. 少用宏,多用 const 、m enum 和 和 inline

      #define PAI 3.141519 const double PAI = 3.14159; #define ERROR_FILE -1 #define ERROR_MEM

     -2 enum {

      ERROR_FILE = -1,

      ERROR_MEM = -2 }; #define max(a,b) ((a)>(b)?(a):(b)) inline int double max (double a, double b) {

      return a > b ? a : b; }

     2. 变量随用随声明同时初始化。

     3. 少用 malloc/free ,多用 new/delete 。

     4. 少用 C C 风格的强制类型转换,多用类型转换运算符。

     5. 少用 C C 风格的字符串,多用 string 。

     6. 树立面向对象的编程思想。

      - 20 - 附加:

     g string 类:

     例子:

     #include <iostream> #include <cstring> #include <cstdio> using namespace std; int main (void) {

     string s1 ("hello");

     string s2 = "world";

     (s1 += " ") += s2;

     cout << s1 << endl;

     string s3 = s1;

     cout << s3 << endl;

     cout << (s1 == s3) << endl;

     s3[0] = "H";

     cout << s3 << endl;

     cout << (s1 > s3) << endl;

     cout << s1.length () << endl;

     cout << (s1 == s3) << endl;

     cout << (strcasecmp (s1.c_str (),

      s3.c_str ()) == 0) << endl;

     cout << sizeof (s1) << endl;

     FILE* fp = fopen ("string.txt", "w"); // fwrite (&s3, sizeof (s3), 1, fp);

     fwrite (s3.c_str (), sizeof (char),

      s3.length (), fp);

     fclose (fp);

     return 0; }

      - 21 -

      第二课

     类和对象

     一、什么是对象

     1.万物皆对象 2.程序就是一组对象,对象之间通过消息交换信息 3.类就是对对象的描述和抽象,对象就是类的具体化和实例化 二 、通过类描述对象

     属性:姓名、年龄、学号 行为:吃饭、睡觉、学习 类就是从属性和行为两个方面对对象进行抽象。

     三、面向对象程序设计 (OOP)

     现实世界

      虚拟世界 对象

     -> 抽象 -> 类 -> 对象 1.至少掌握一种 OOP 编程语言 2.精通一种面向对象的元语言—UML 3.研究设计模式,GOF

      四、类的基本语法

     1. 类的定义

     class 类名 { }; 如 class Student { }; 2. 成员变量 —— 属性

     class 类名 {

      类型 成员变量名; }; 如 class Student {

      string m_name;

      int

     m_age; }; 3. 成员函数 —— 行为

     class 类名 {

      返回类型 成员函数名 (形参表) {

      函数体;

      } };

      - 22 - 如 class Student {

      string m_name;

      int

     m_age;

      void eat (const string& food) {

      ...

      } }; 4. 访问控制属性

     1)公有成员:public,谁都可以访问。

     2)私有成员:private,只有自己可以访问。

     3)保护成员:protected,只有自己和自己的子类可以访问。

     4)类的成员缺省访控属性为私有,而结构的成员缺省访控属性为公有。

     例子:

     #include <iostream> using namespace std; class Student { private:

      // 声明为私有部分

     string m_name;

     int m_age; public:

      // 声明为私有部分

     void eat (const string& food) {

      cout << m_age << "岁的" << m_name

     << "同学正在吃" << food << "。" << endl;

     }

     void setName (const string& name) {

     // 为接口

      if (name == "2")

     cout << "你才" << name << "!" << endl;

      else

     m_name = name;

     }

     void setAge (int age) {

     // 为接口

      if (age < 0)

     cout << "无效的年龄!" << endl;

      else

     m_age = age;

     } }; int main (void) {

     Student student;

     student.setName ("2");

     // 你才 2 2

      student.setAge (-100);

     // 无效年龄

      student.setName ("张飞"); // 将其赋值给成员变量 m_name

      - 23 -

     student.setAge (20);

     // 将其赋值给 成员变量 m_age

      student.eat ("包子");

     0 //20 岁的张飞同学正在吃包子

      return 0; }

     5. 构造函数

     class {

      ...

      类名 (行参表)

     {

      构造函数体;

      } }; 当一个对象被创建时,构造函数会自动被执行,其参数来自构造实参。

     6. 构造函数可以通过构造参数实现重载。

     7. 如果一个类没有定义任何构造函数,那么系统就会缺省地为其提供一个无参构造函数,该构造函数对于基本类型的成员变量不做初始化,对于类类型的成员变量,调用其相应类型的无参构造函 数初始化。

     8. 对象创建过程

     分配内存->调用构造函数->调用类类型成员的构造函数->构造函数的代码

     9. 初始化表

     class 类名 {

      类名(...) :初始化表 {

      构造函数体

     } }; const int x = 100; x = 100; int& a = b; a = b; 1) 如果类中含有常量或引用型的成员变量,必须通过初始化表对其初始化。

     2)成员变量的初始化顺序仅于其被声明的顺序有关,而与初始化表的顺序无关。

     class A { public:

      A (char* psz) : m_str (psz),

     m_len (m_str.length()) {} private:

     size_t m_len;

     string m_str; }

      - 24 - 例子 1 1 :类的声明与定义以及使用可以不在一个文件

     这是 h s.h 文件

     #ifndef _S_H #define _S_H #include <string> using namespace std; // 声明 t Student 类

     class Student { public:

     Student (const string& name = "", int age = 0);

     void eat (const string& food); private:

     string m_name;

     int m_age; }; #endif // _S_H

     这是 p s.cpp 文件

     #include <iostream> using namespace std; #include "s.h" // 实现 t Student 类

     Student::Student (const string& name /* = "" */,

     int age /* = 0 */) : m_name (name),

     m_age (age) {} void Student::eat (const string& food) {

     cout << m_name << "," << m_age << "," << food

      << endl; }

      这是 p main.cpp 文件:

     #include "s.h" // 使用 t Student 类

     int main (void) {

     Student s ("张飞", 25);

     s.eat ("包子");

     return 0; } ---------------------------------------------------

      - 25 - 例子 2 2 :不同的构造函数

     #include <iostream> using namespace std; class A { public:

     A (int a) {} }; class Student { private:

     string m_name;

     int m_age;

     A m_a;

     // 类类型的成员变量 public:

     void eat (const string& food) {

      cout << m_age << "岁的" << m_name

     << "同学正在吃" << food << "。" << endl;

     }

     // void _ZN7Student3eatERKSs (Student* this, //

     const string& food) { //

     cout << this->m_age << "岁的"<<this->m_name //

     << "同学正在吃" << food << "。" << endl; //

     }

      // 这是计算机中编译的 样子

      void setName (const string& name) {

      if (name == "2")

     cout << "你才" << name << "!" << endl;

      else

     m_name = name;

     }

     void setAge (int age) {

      if (age < 0)

     cout << "无效的年龄!" << endl;

      else

     m_age = age;

     }

      // 如果同时有多种构造函数存在,则根据构造参数来确定调用哪 个构造函数,既构造函数可以通过构造参数实现重载

     // 构造函数

      Student (const string& name, int age) :

      m_a (100) {

      m_name = name;

      - 26 -

      m_age = age;

     }

      // 无参构造

     Student (void) : m_a (100) {

      // 没有参数

     m_name = "没名";

      m_age = 0;

     }

      // 单参构造

      Student (const string& name) : m_a (100),

      m_name (name),

     m_age (0) {

      m_name = "哈哈";

     } }; int main (void) {

     Student s1 ("张飞", 25);

     s1.eat ("包子"); // _ZN7Student3eatERKSs (&s1, "包子");

      // 编译器中的样子

     Student s2 = Student ("赵云", 22);

     s2.eat ("烧饼"); // _ZN7Student3eatERKSs (&s2, "烧饼"); // 编译器中的样子

      Student s3;

     // 调用的无参构造

      s3.eat ("煎饼果子");

      Student* s4 = new Student ("关羽", 30); // 调用有参构造,分配内存,并初始化

      s4->eat ("烤鸭"); // 当访问地址(指针或迭代器)的成员或数据时,用- -> >

      delete s4;

     Student& s5 = *new Student (); // 调用无参构造初始化

      s5.eat ("面条");

     // 当访问直接对象的成员或数据时,用“. . ”

      delete &s5;

      Student sa1[3] = {s1, s2};

     //用 用 1 s1 与 与 2 s2 给数组初始化,但第三个元素没有赋值

      sa1[0].eat ("KFC");

      5 //25 岁的张飞同学正在吃 KFC

      sa1[1].eat ("KFC");

      2 //22 岁的赵云同学正在吃 KFC

     sa1[2].eat ("KFC");

      0 //0 岁的无名同学 正在吃 KFC

      Student* sa2 = new Student[3] {s1, s2}; 1 // c++2011 支持

      sa2[0].eat ("KFC");

     sa2[1].eat ("KFC");

      - 27 -

     sa2[2].eat ("KFC");

     delete[] sa2;

      Student s6 ("刘备"); // 调用单参构造

      s6.eat ("米饭");//

     return 0; } ----------------------------------------------- 练习 : 实 现一个 k Clock 类支持两种工作模式,计时器和电子钟。

     00:01:00 14:05:37 #include <iomanip> cout << setw(4) << setfill("0") << 12; 0012 Clock

      时、分、秒

      走 - 显示、滴答

     练习答案:

     #include <iostream>

     #include <iomanip>

     using namespace std;

     class Clock {

     public:

     Clock (bool timer = true) :

     m_ hour (0), m_min (0), m_sec (0) {

     if (! timer) {

     time_t t = time (NULL);

     tm* local = localtime (&t);

     m_hour = local- - >tm_hour;

     m_min = local- - >tm_min;

     m_sec = local- - >tm_sec;

     } }

     } }

     void run (void) {

     for (;;) {

     show ();

     tick ();

     } }

     } }

     private:

     void show (void) {

      - 28 -

      cout << "\ \ r" << setfill ("0")

     << setw (2) << m_hour << ":"

     << setw (2) << m_min << ":"

     << setw (2) << m_sec << flush;

     //

     printf ("\ \ r%02d:%02d:%02d", m_hour,

     //

     m_min, m_sec);

     } }

     void tick (void) {

     sleep (1);

     if (++m_sec == 60) {

     m_sec = 0;

     if (++m_min == 60) {

     m_min = 0;

     if (++m_hour == 24)

     m_hour = 0;

     } }

     } }

     } }

     int m_hour;

     int m_min;

     int m_sec;

     };

     int main (void) {

     Clock clock (false);

     clock.run ();

     return 0;

     } }

     ------------------- ------------------

      - 29 - 五、s this 指针

     1.一般而言,在类的构造函数或成员函数中,关键字 this 表示一个指针,对于构造函数而言,this 指向正在被构造的对象,对于成员函数而言,this 指向调用该函数的对象。

     2.this 指针的用途 1)在类的内部区分成员变量。

     2)在成员函数中返回调用对象自身。

     3)在成员函数内部通过参数向外界传递调用对象自身,以实现对象间交互。

     老 -问题-> 学 师 <-答案- 生 class A {

     B m_b; }; class B {

     A m_a; }; sizeof(A)

     //error class C {

     C m_c; }; 例子 1 1 :

     #include <iostream> using namespace std; class A { public:

     A (int data) : data (data) {

      cout << "构造: " << this << endl; //

     this->data = data;

     }

     void foo (void) {

      cout << "foo: " << this << endl;

      cout << this->data << endl;

     }

     int data; }; int main (void) {

     A a (1000);

     // 创建对象调用了构造函数,并输出 s this 的地址,输出“构造:0xbf9b24d8 ”

     cout << "main: " << &a << endl; // 输出该对象的地址,输出“ main:0xbf9b24d8 ”

     a.foo () ;

      // 该对象调用 o foo 函数,输出 s this 的值,以及输出 this- -> > data的值,输出“ foo :

     0xbf9b24d8

     1000 ”

     A* pa = new A (1000);

      // 创建对象调用构造函数,输出 s this 的地址,输出“构造:

      - 30 - 0x95cc008 ”

     cout << "main: " << pa << endl; // 输出该对象的地址,输出“ main :

     0x95cc008 ”

     pa->foo ();

      // 该对象调用 o foo 函数,输出 s this 以及 this- -a >data 的值,输出“ foo :

     0x95cc008

     1000 ”

     delete pa; } --------------------------------------------------- 例子 2 2 :

     #include <iostream> using namespace std; class Counter { public:

     Counter (void) : m_data (0) {}

     Counter& inc (void) {

      // 返回的是一个别名,不加& & 的话,返回的就是一个拷贝

     ++m_data;

      return *this;

     }

     void print (void) {

      cout << m_data << endl;

     } private:

     int m_data; }; int main (void) {

     Counter c; // c.inc (); // c.inc (); // c.inc ();

     c.inc ().inc ().inc (); // 函数返回的是一个别名,是一个左值,可以用来调用函数

      c.print ();

     // 输出为 3 3 ,如果前面的函数不加& & ,返回的只是拷贝,输出为1 1 。

      return 0; }

      - 31 - 例子 3 3 :学生与老师

     #include <iostream> using namespace std; class Student;

      // 因为在 r Teacher 中会用到 Student ,所以提前声明一下

     class Teacher { public:

     void educate (Student* s); // 可以声明在类的内部,定义在类的外部

     void reply (const string& answer) {

      m_answer = answer;

     } private:

     string m_answer; }; class Student { public:

     void ask (const string& question, Teacher* t) {

      cout << "问题:" << question << endl;

      t->reply ("不知道。");

     } }; void Teacher::educate (Student* s) {

     s->ask ("什么是 this 指针?", this); // 将问题 n question 和 和 r Teacher 类变量的地址作为参数传递给 t Student 类中的 ask k 成员函数,并在 k ask 函数中得到一个值作为参数传递给 Teacher类中的 y replay 函数,将值赋给 m_answer ,最后完成输出。

      cout << "答案:" << m_answer << endl; } int main (void) {

     Teacher t;

     Student s;

     t.educate (&s);

     return 0; } ---------------------------------------------

      - 32 - 六、常函数与常对象

     1.如果在一个类的成员函数的参数表后面加上 const 关键字,那么这个成员函数就被成为常函数,常函数的 this 指针是一个常指针。在常函数内部无法修改成员变量,除非该变量具有 mutable 属性。而且在常函数内部也无法调用非常函数。

     2.常对象:拥有 const 属性的对象,兑现引用或指针。

     常对象只能调用常函数。

     同型的常函数和非常函数可以构成重载关系。常对象调用常版本,非常对象调用非常版本。如果没有非常版本,非常对象也可以调用常版本。

     const XXX 函数名 (const YYY yyy) const {

      ... } 例子:

     #include <iostream> using namespace std; class A { public: // void bar (void) {

      // 函数 1 1 //

     cout << "非常 bar" << endl; // } // 函数 1 1 与函数 2 2 构成函数重载

      void bar (void) const {

     // 函数 2 2

      cout << "常 bar" << endl;

     } //

     void XXXbarYYY (A* this) {}

     void foo (void) const {

     // 函数 3 3

     //

      m_i = 100;

     // 在常函数内部无法修改成员变量,除非那个成员变量有 e mutable 属性,例:

     mutable int m_i;

     const_cast<A*>(this)->m_i = 100; // 也可以通过去常来解决

      }

     void print (void) const {

      cout << m_i << endl;

     } // _ZNK1A3fooEv (const A* this) { //

     const_cast<A*>(this)->m_i = 100; // }

     int m_i; }; void func (void) /*const*/ {} int main (void) {

     A a;

     a.foo ();

     // 调用的是函数 3 3

      - 33 -

     a.print (); // “ 100 ”

     const A& r = a;r //r 为常对象,a a 为非常对象

      r.bar (); // “常 bar ”,r r 为常对象,常对象只能调用常函数

     //

     XXXbarYYY (&r); // const A*

      a.bar (); // “常 bar ”,a a 为非常对象,可以调用常函数,也 可调用非常函数 // XXXbarYYY (&a); // A*

     return 0; } ---------------------------------------------

     七、析构函数

     class 类名 {

      ~类名 (void) {

     析构函数体;

      } }; 当一个对象被销毁时自动执行析构函数。

     局部对象离开作用域时被销毁,堆对象被 delete 时被销毁。

     如果一个类没有定义任何析构函数,那么系统会提供一个缺省析构函数。缺省析构函数对基本类型的成员变量什么也不干,对类类型的成员变量,调用相应类型的析构函数。

     一般情况下,在析构函数中释放各种动态分配的资源。

     构造: 基类->成员->子类 析构: 子类->成员->基类 例子:

     #include <iostream> using namespace std; class Double { public:

     Double (double data) :

      m_data (new double (data)) {

      cout << "构造" << endl;

     } // 构造函数早开始时执行,既创建对象时执行

      ~Double (void) {

      cout << "析构" << endl;

      delete m_data;

     } // 析构函数在对象结束时执行

      void print (void) const {

      cout << *m_data << endl;

     }

      - 34 - private:

     double* m_data;

     string m_lable; }; int main (void) { //

     {

      Double d1 (3.14);

      d1.print (); // “构造 ,3.14 ”(1 d1 调用的构造)

     // }

     Double* d2 = new Double (1.23); // “构造”(2 d2 调用的构造)

      delete d2;

      // “析构”(2 d2 调用的析构)

     cout << "再见!" << endl; // “再见”

      return 0;

      // “析构”,(程序结束,1 d1 调用的析构)

     } -----------------------------------------------------------------------------------八、拷贝构造函数和拷贝赋值运算符

     1. 拷贝构造:用一个已有的对象,构造和它同类型的副本对象——克隆。

     2. 拷贝构造函数

     形如 class X {

      X (const X& that) { ... } }; 的构造函数成为 拷贝构造函数 。如果一个类没有定义拷贝构造函数,系统会提供一个缺省拷贝构造函数。缺省拷贝构造函数对于基本类型的成员变量,按字节复制,对于类类型的成员变量,调用相应类型的拷贝构造函数。

     3. 在某些情况就下, 缺省拷贝构造函数只能实现浅拷贝 ,如果需要获得深拷贝的复制效果,就需要 自己定义拷贝构造函数 。

      例子:拷贝函数

     #include <iostream> using namespace std; class Integer { public:

     Integer (int data = 0) : m_data (data) {} // 构造函数

      void print (void) const {

      cout << m_data << endl;

     }

      - 35 - // 拷贝构造(自己定义的):

      Integer (const Integer& that) :

      m_data (that.m_data) {

      cout << "拷贝构造" << endl;

     }

      private:

     int m_data; }; void foo (Integer i) {

     //用 用 r Inerger 类变量时实参给函数中 r Interger 类的形参赋值,同样会调用拷贝构造函数

      i.print (); } Integer bar (void) {

     Integer i;

     return i; } int main (void) {

     Integer i1 (10);

     i1.print (); // 正常创建对象,输出“ 10 ”

      Integer i2 (i1); // 调用拷贝构造,输出“拷贝构 造”

      i2.print ();

     // 调用 t print 函数,输出“ 10 ”

      Integer i3 = i1; // 调用拷贝构造,输出“拷贝构造”

     i3.print ();

     // 调用 t print 函数,输出“ 10 ” //

     Integer i4 (10, 20);

      cout << "调用 foo()函数" << endl;

     foo (i1);

      // 调用拷贝构造函数,且调用 t print 函数输出,所以输出为“拷贝构造

     10” ”

     cout << "调用 bar()函数" << endl;

     Integer i4 (bar ());

     return 0; } ---------------------------------------------------

      - 36 - 4. 拷贝赋值运算符函数

     形如 class X {

      X& operator= (const X& that) {

      ...

      } }; 的成员函数称为 拷贝赋值运算符函数。如果一个类没有定义拷贝赋值运算符函数,系统会提供一个缺省拷贝赋值运算符函数。缺省拷贝赋值运算符函数对于基本类型的成员变量,按字节复制,对于类类型的成员变量,调用相应类型的拷贝赋值运算符函数。

     5.在某些情况就下,缺省拷贝赋值运算符函数只能实现浅拷贝,如果需要获得深拷贝的复制效果,就需要自己定义拷贝赋值运算符函数。

      例子:拷贝赋值运算符函数

     #include <iostream> using namespace std; class Integer { public:

     Integer (int data) : m_data (new int (data)) {} // 构造函数

      ~Integer (void) {

     // 析构函数

      if (m_data) {

     delete m_data;

     m_data = NULL;

      }

     }

     void print (void) const {

      cout << *m_data << endl;

     }

     Integer (const Integer& that) :

      // 拷贝构造函数

     m_data (new int (*that.m_data)) {}

     void set (int data) {

      *m_data = data;

     }

      - 37 - // 拷贝赋值运算符函数(运算符重载)

      Integer& operator= (const Integer& that) {

     // 防止自赋值

      if (&that != this) {

     // 释放旧资源

     delete m_data;

     // 分配新资源

     m_data = new int (*that.m_data);

      // 拷贝新数据

      }

     // 返回自引用

      return *this;

     } private:

     int* m_data; }; int main (void) ...

    推荐访问:笔记