标签:
本文是学习谭浩强老师的《c++程序设计》后的笔记。
c++由c发展而来的,与c兼容。用c语言写的程序可以不加修改用于c++。从c++的名字可以看出它是c的超集。c++即可用于面向过程的程序设计,又可用于面向对象的程序设计,是一种功能强大的混合型程序设计语言。
c++与c语言最大的区别在于: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 }
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个主要特征:抽象、封装、继承、多态。
(1)抽象
将事物的属性和行为抽象成一种数据类型,这种类型就成为类(class)。类是对象的抽象,而对象时类的实例。
(2)封装
封装有两方面的含义:一是将相关的数据和函数封装在一个对象中,形成一个基本单元,各个对象相互独立,互不干扰;二是将对象中的某些部分对外隐藏,隐藏其中的细节,只留下少量的接口,和外界交互。
这样做的好处是:大大降低操作对象的复杂程度,并且有利于数据的安全,防止无关的人员访问和修改数据。
(3)继承
子类继承父类的成员(属性、方法),目的是减少程序设计,实现“软件重用”的思想。
(4)多态
所谓多态性指:由继承而产生的相关的不用类,其父对象对同一消息做出不同的响应,目的是增加软件的灵活性。
类是对象的抽象,是一种类型;对象是类的实例。如同结构体类型和结构体变量的关系一样。
类是抽象的,不占内存空间;对象是具体的,占存储空间。
1 class 类名 2 { 3 public: 4 公共的成员属性和方法 5 6 private: 7 私有成员属性和方法 8 };
(1)private:私有的成员属性和方法,只能在类中或者类的作用域中使用(友元除外)。
(2)public:公共的成员属性和方法,不仅在类中或者类的作用域中使用,还可以在类外面使用。
(3)protected:受保护的成员属性和方法,和private一样,只能在类中或者类的作用域中使用(友元除外),不同之处的区别在继承中体现。
(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 Student 2 { 3 public: 4 ...... 5 6 private: 7 ...... 8 }stu1, stu2;
(3)不出现类名,直接定义对象
1 class 2 { 3 public: 4 ...... 5 6 private: 7 ....... 8 }stu1, stu2;
相同点: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 };
在类的作用域中叫成员函数,不在类的作用域叫普通函数。
如果在类的外面定义成员函数,需要加上作用域运算符 :: 。
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 }
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 //声明需要显示inline 14 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 }
对象的数据部分是分开的,函数部分是公共的
(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();
(1)公共接口和私有接口要分离;
(2)属性一般设置成private,需要访问和修改数据定义函数接口;
(3)类函数声明和成员函数的实现分离,类声明放在头文件中,实现放在.cpp中。
在创建一个对象时,需要对数据成员初始化。
如果一个类中所有的成员都是public,则可以在定义对象时对数据成员初始化。
如果类中有private和protected的数据成员,不能用这种方式,必须用构造函数初始化。
1 class Time 2 { 3 public: 4 int hour; 5 int minute; 6 int sec; 7 } 8 9 Time t = {8, 8, 8};
构造函数是初始化对象的数据
(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 }
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 }
在一般情况下,调用析构函数的顺序与构造函数的次序相反:最先调用的构造函数,与其对应的析构函数最后被调用;最后调用的构造函数,与其对应的析构函数最先被调用。
但是,并不是任何情况下都是按这一原则处理的,需要考虑对象的作用域和存储类型。
(1)全局对象:在main函数前,执行构造函数,在程序终止时,调用析构函数。
(2)局部对象:在建立对象时,调用构造函数,在作用域结束后,调用析构函数。
(3)static局部对象:在第一次使用该对象,调用构造函数,在程序终止时,调用析构函数。
数组不仅可以由简单数据类型组成,还可以由对象组成。
如有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 }
(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 }
每个对象都有一个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 }
(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;
引用相当于变量的别名。实际上,变量名和引用指向同一段内存单元,引用不占任何空间。
1 Time t; //定义一个Time类的对象t 2 Time &t1 = t; //t1是t的引用
在需要这个对象的时候创建,不需要的时候释放,并释放它所占的内存空间,提高内存空间的利用率。
用new运算符动态创建对象,用delete运算符销毁对象。
1 Time *p = new Time; 2 3 delete p;
(1)静态数据成员
staic静态数据成员被所有对象共用,在内存中占一块空间。
只要在类中定义了static静态数据成员,即使不定义对象,也会分配空间,可以被引用。
static静态数据成员在程序开始时被分配空间,在程序结束时才释放空间。
static静态数据成员可以被初始化,但只能在类外进行初始化,其一般形式:类::静态成员名 = 初值;不必加static,如果未赋初值,则为0。
static静态数据成员既可以用对象名引用,也可以用类名引用。
(2)静态成员函数
友元可以访问其友好关系类中的私有成员。
友元包括:友元函数和友元类。
(1)将普通函数变成友元函数
(2)将成员函数变成友元函数
(3)友元类
如果有两个或者多个类的功能是相同的,仅仅是数据类型不同,则用类模板。
在c++程序设计中,多态性是指具有不同功能的函数可以用同一函数名,这样就可以用同一函数名调用不同内容的函数;在面向对象方法中,多态性是指不同的对象接受到同一消息产生不同的行为(方法)。
多态性分2种:静态多态性和动态多态性。函数的重载和运算符重载是静态多态性,在程序编译时决定调用哪个函数,因此静态多态也叫编译时多态;动态多态性是在程序运行过程中才动态确定的,因此动态多态性也叫运行时多态。动态多态性是通过虚函数(virtual)实现的。
标签:
原文地址:http://www.cnblogs.com/gaoningbo/p/5768799.html