首页 > 代码库 > 《c++程序设计》笔记
《c++程序设计》笔记
本文是学习谭浩强老师的《c++程序设计》后的笔记。
1.概述
c++由c发展而来的,与c兼容。用c语言写的程序可以不加修改用于c++。从c++的名字可以看出它是c的超集。c++即可用于面向过程的程序设计,又可用于面向对象的程序设计,是一种功能强大的混合型程序设计语言。
c++与c语言最大的区别在于:c++增加了面向对象的机制。
2. 一个简单的c++程序
1 #include <iostream> 2 3 using namespace std; 4 5 int main() 6 { 7 cout << "This is a C++ program." << endl; 8 9 return 0;10 }
3. 包含类的c++程序
1 #include <iostream> 2 3 using namespace std; 4 5 class Student 6 { 7 public: 8 Student() 9 {10 num = 0;11 score = 0;12 }13 14 void setData();15 void display();16 17 private:18 int num;19 int score;20 };21 22 void Student::setData()23 {24 cin >> num >> score;25 26 return;27 }28 29 void Student::display()30 {31 cout << "num:" << num << " score:" << score << endl;32 33 return;34 }35 36 int main()37 {38 Student stu;39 40 stu.setData();41 stu.display();42 43 return 0;44 }
4. c++的特性
面对对象程序设计有4个主要特征:抽象、封装、继承、多态。
(1)抽象
将事物的属性和行为抽象成一种数据类型,这种类型就成为类(class)。类是对象的抽象,而对象时类的实例。
(2)封装
封装有两方面的含义:一是将相关的数据和函数封装在一个对象中,形成一个基本单元,各个对象相互独立,互不干扰;二是将对象中的某些部分对外隐藏,隐藏其中的细节,只留下少量的接口,和外界交互。
这样做的好处是:大大降低操作对象的复杂程度,并且有利于数据的安全,防止无关的人员访问和修改数据。
(3)继承
子类继承父类的成员(属性、方法),目的是减少程序设计,实现“软件重用”的思想。
(4)多态
所谓多态性指:由继承而产生的相关的不用类,其父对象对同一消息做出不同的响应,目的是增加软件的灵活性。
5. 类和对象
5.1 类和对象的关系
类是对象的抽象,是一种类型;对象是类的实例。如同结构体类型和结构体变量的关系一样。
类是抽象的,不占内存空间;对象是具体的,占存储空间。
5.2 声明类类型
1 class 类名2 {3 public:4 公共的成员属性和方法5 6 private:7 私有成员属性和方法 8 };
5.3 成员访问限定符:
(1)private:私有的成员属性和方法,只能在类中或者类的作用域中使用(友元除外)。
(2)public:公共的成员属性和方法,不仅在类中或者类的作用域中使用,还可以在类外面使用。
(3)protected:受保护的成员属性和方法,和private一样,只能在类中或者类的作用域中使用(友元除外),不同之处的区别在继承中体现。
5.4 定义类对象
(1)先声明类类型,然后在定义对象
1 class Student 2 { 3 public: 4 ...... 5 6 private: 7 ...... 8 }; 9 10 //带class定义对象11 class Student stu1, stu2;12 13 //不带class定义对象 (推荐这种形式)14 Student stu1, stu2;
(2)声明类型的同时,定义对象
1 class Student2 {3 public:4 ......5 6 private:7 ......8 }stu1, stu2;
(3)不出现类名,直接定义对象
1 class2 {3 public:4 ......5 6 private:7 .......8 }stu1, stu2;
5.5 类和结构体的异同
相同点:class的关键字可以由struct代替。
class和struct的不同点在于:
(1)class默认的成员是private;
(2)struct默认的成员是public。
1 class Student 2 { 3 //私有的 4 int num; 5 int score 6 }; 7 8 struct Student 9 {10 //公共的11 int num;12 int score;13 };
5.6 成员函数
在类的作用域中叫成员函数,不在类的作用域叫普通函数。
如果在类的外面定义成员函数,需要加上作用域运算符 :: 。
1 class Student 2 { 3 public: 4 //在类中定义 5 void setData() 6 { 7 cin >> num >> score; 8 9 return;10 }11 12 //在类中声明,在类的作用域定义13 void display();14 15 private:16 int num;17 int score;18 };19 20 //在类的作用域定义,需要加上作用域运算符21 void Student::dispaly()22 {23 cout << "num:" << num << " score:" << score << end;24 25 return;26 }
5.7 inline内联函数
inline内联函数和宏函数一样,都是直接在代码中展开,节省了函数带来的开销。
inline比宏函数的优势在于:inline内联函数是成员函数,可以访问类的成员,而宏函数做不到
使用inline内联函数的条件:
(1)代码量少;
(2)调用频繁
1 class Student 2 { 3 public: 4 //如果在类中定义,默认是inline函数 5 //inline关键字可以不显示 6 void setData() 7 { 8 cin >> num >> score; 9 10 return;11 }12 13 //声明需要显示inline14 inline void display();15 16 private:17 int num;18 int score;19 };20 21 inline void Student::display()22 {23 cout << "num:" << num << " score:" << score << endl;24 25 return;26 }
5.8 对象的存储方式
对象的数据部分是分开的,函数部分是公共的
5.9 对象成员的引用
(1)通过对象名和成员运算符访问
1 Student stu;2 3 stu.setData();
(2)通过指向对象的指针访问
1 Student stu;2 Student *s = &stu;3 4 s->setData();
(3)通过对象的引用访问
1 Student stu;2 Student &s = stu;3 4 s.setData();
5.10 如何设计一个优秀的类
(1)公共接口和私有接口要分离;
(2)属性一般设置成private,需要访问和修改数据定义函数接口;
(3)类函数声明和成员函数的实现分离,类声明放在头文件中,实现放在.cpp中。
6. 对类和对象的进一步讨论
6.1 对象的初始化
在创建一个对象时,需要对数据成员初始化。
如果一个类中所有的成员都是public,则可以在定义对象时对数据成员初始化。
如果类中有private和protected的数据成员,不能用这种方式,必须用构造函数初始化。
1 class Time2 {3 public:4 int hour;5 int minute;6 int sec;7 }8 9 Time t = {8, 8, 8};
6.2 构造函数
构造函数是初始化对象的数据
(1)不带参数的构造函数,在类中定义
1 class Time 2 { 3 public: 4 //在类中定义构造函数,内联函数 5 Time() 6 { 7 hour = 0; 8 minute = 0; 9 sec = 0;10 }11 12 private:13 int hour;14 int minute;15 int sec;16 };17 18 int main()19 {20 Time t;21 22 return 0;23 }
(2)不带参数的构造函数,在类外定义
1 class Time 2 { 3 public: 4 Time(); 5 6 private: 7 int hour; 8 int minute; 9 int sec;10 };11 12 //在类外定义构造函数13 Time::Time()14 {15 hour = 0;16 minute = 0;17 sec = 0;18 }
(3)带参数的构造函数
1 class Time 2 { 3 public: 4 Time(int h, int m, int s) 5 { 6 hour = h; 7 minute = m; 8 sec = s; 9 }10 11 private:12 int hour;13 int minute;14 int sec;15 };16 17 int main()18 {19 Time t(8,8,8);20 21 return 0;22 }
(4)用参数初始化表对数据成员初始化
1 class Time 2 { 3 public: 4 Time(int h, int m, int s) 5 :hour(h),minute(m),sec(s) 6 { 7 8 } 9 10 private:11 int hour;12 int minute;13 int sec;14 };15 16 int main()17 {18 Time t(8, 8, 8);19 20 return 0;21 }
(5)构造函数的重载
1 class Time 2 { 3 public: 4 Time() 5 { 6 hour = 0; 7 minute = 0; 8 sec = 0; 9 }10 11 Time(int h, int m, int s)12 {13 hour = h;14 minute = m;15 sec = s;16 }17 18 private:19 int hour;20 int minute;21 int sec;22 };23 24 int main()25 {26 Time t1;27 Time t2(8, 8, 8);28 29 return 0;30 }
(6)使用默认参数的构造函数,带默认参数的函数不能重载
1 class Time 2 { 3 public: 4 Time(int h = 8, int m = 8, int s = 8) 5 { 6 hour = h; 7 minute = m; 8 sec = s; 9 }10 11 private:12 int hour;13 int minute;14 int sec;15 };16 17 int main()18 {19 Time t1; //没有参数20 Time t2(8); //一个参数21 Time t3(8, 8); //二个参数22 Time t4(8, 8, 8); //三个参数23 24 return 0;25 }
6.2 析构函数
1 class Time 2 { 3 public: 4 //构造函数 5 Time() 6 { 7 hour = 0; 8 minute = 0; 9 sec = 0;10 }11 12 //析构函数13 ~Time()14 {15 16 }17 18 private:19 int hour;20 int minute;21 int sec;22 };23 24 int main()25 {26 Time t;27 28 return 0;29 }
6.3 调用构造函数和析构函数的顺序
在一般情况下,调用析构函数的顺序与构造函数的次序相反:最先调用的构造函数,与其对应的析构函数最后被调用;最后调用的构造函数,与其对应的析构函数最先被调用。
但是,并不是任何情况下都是按这一原则处理的,需要考虑对象的作用域和存储类型。
(1)全局对象:在main函数前,执行构造函数,在程序终止时,调用析构函数。
(2)局部对象:在建立对象时,调用构造函数,在作用域结束后,调用析构函数。
(3)static局部对象:在第一次使用该对象,调用构造函数,在程序终止时,调用析构函数。
6.4 对象数组
数组不仅可以由简单数据类型组成,还可以由对象组成。
如有3个Student对象,则可以用 Student s[3]表示。
如果构造函数只有一个参数,则可以 Student s[3] = {1, 2, 3},三个参数分别传给三个对象的构造函数。
如果有多个参数,应该这样定义Student s[3] = {Student(1, 100), Student(2, 99), Student(3, 98)};
1 #include <iostream> 2 3 using namespace std; 4 5 class Student 6 { 7 public: 8 Student(int n = 0, int s = 0):num(n), score(s){}; 9 10 void display();11 12 private:13 int num;14 int score;15 };16 17 void Student::display()18 {19 cout << "num:" << num << " score:" << score << endl;20 21 return;22 }23 24 int main()25 {26 Student s[3] = {27 Student(0, 100),28 Student(1),29 Student(),30 };31 32 for (int i = 0; i < 3; i++)33 {34 s[i].display();35 }36 37 return 0;38 }
6.5 对象指针
(1)指向对象的指针
(2)指向对象数据成员的指针
(3)指向对象函数成员的指针
1 #include <iostream> 2 3 using namespace std; 4 5 class Time 6 { 7 public: 8 Time(int h, int m, int s) 9 :hour(h),minute(m),sec(s)10 {11 12 }13 14 void getTime();15 16 public:17 int hour;18 int minute;19 int sec;20 };21 22 void Time::getTime()23 {24 cout << "hour:" << hour << " ";25 cout << "minute:" << minute << " ";26 cout << "sec:" << sec << endl;27 28 return;29 }30 31 int main()32 {33 Time t(8, 8, 8); //定义一个Time类的对象34 Time *p = &t; //定义指向t的指针35 p->getTime();36 37 int *p1 = &t.hour; //定义指向对象数据成员的指针38 cout << "hour:" << *p1 << endl;39 40 void (Time::*p3)(void) = &Time::getTime; //定义指向对象函数成员的指针41 (t.*p3)();42 43 return 0;44 }
6.6 this指针
每个对象都有一个this的隐藏指针,当对象调用函数时,会把这个this传进去,这是编译器做的事情。
1 Time(int h, int m, int s)2 {3 this->hour = h;4 this->minute = m;5 this->sec = s;6 7 return;8 }
6.7 const
(1)常对象
定义常对象的一般格式为:类名 const 对象名;const 类名 对象名。
如果一个对象被声明为常对象,则不能调用该对象的非const成员函数(除了由系统隐式调用的构造函数和析构函数)。
(2)常数据成员
常数据成员的初始化,只能在构造函数中通过参数初始化表进行初始化。
1 const int hour; //定义const成员变量2 3 Time(int h):hour(h){}
(3)常成员函数
如果将成员函数声明为常成员函数,则只能引用类中的数据成员,而不能修改它们,例如只用于输出数据等。
const的位置在函数名和()之后。在声明和定义加上const,但是在调用不必加const。
1 void getTime() const;
6.8 对象引用
引用相当于变量的别名。实际上,变量名和引用指向同一段内存单元,引用不占任何空间。
1 Time t; //定义一个Time类的对象t2 Time &t1 = t; //t1是t的引用
6.9 对象的动态建立和释放
在需要这个对象的时候创建,不需要的时候释放,并释放它所占的内存空间,提高内存空间的利用率。
用new运算符动态创建对象,用delete运算符销毁对象。
1 Time *p = new Time;2 3 delete p;
6.10 对象的赋值和复制
6.11 static静态成员
(1)静态数据成员
staic静态数据成员被所有对象共用,在内存中占一块空间。
只要在类中定义了static静态数据成员,即使不定义对象,也会分配空间,可以被引用。
static静态数据成员在程序开始时被分配空间,在程序结束时才释放空间。
static静态数据成员可以被初始化,但只能在类外进行初始化,其一般形式:类::静态成员名 = 初值;不必加static,如果未赋初值,则为0。
static静态数据成员既可以用对象名引用,也可以用类名引用。
(2)静态成员函数
6.12 friend友元
友元可以访问其友好关系类中的私有成员。
友元包括:友元函数和友元类。
(1)将普通函数变成友元函数
(2)将成员函数变成友元函数
(3)友元类
6.13 类模板
如果有两个或者多个类的功能是相同的,仅仅是数据类型不同,则用类模板。
7 运算符重载
8 继承和派生
9 多态性和虚函数
9.1 多态性的概念
在c++程序设计中,多态性是指具有不同功能的函数可以用同一函数名,这样就可以用同一函数名调用不同内容的函数;在面向对象方法中,多态性是指不同的对象接受到同一消息产生不同的行为(方法)。
多态性分2种:静态多态性和动态多态性。函数的重载和运算符重载是静态多态性,在程序编译时决定调用哪个函数,因此静态多态也叫编译时多态;动态多态性是在程序运行过程中才动态确定的,因此动态多态性也叫运行时多态。动态多态性是通过虚函数(virtual)实现的。
《c++程序设计》笔记