上节介绍C++的函数介绍:c++:-1,本节学习类与对象
class 类名称{ public: 公有成员(外部接口) private: 私有成员 protected: 保护型成员};类内初始值举例:
class Clock {public: void setTime(int newH, int newM, int newS); void showTime();private: int hour = 0, minute = 0, second = 0;};//第一种Clock::Clock(int newH,int newM,int newS): hour(newH),minute(newM), second(newS) {}//第二种Clock::Clock(int newH,int newM,int newS){ hour=newH; minute=newM; second=newS;}#include "iostream"using namespace std;class Clock {public: Clock(int newH, int newM, int newS); //构造函数 Clock(); //默认构造函数 void setTime(int newH, int newM, int newS); void showTime();private: int hour, minute, second;};Clock::Clock(): hour(0),minute(0),second(0) { }//默认构造函数//其它函数实现同前int main() { Clock c1(0, 0, 0); //调用有参数的构造函数 Clock c2; //调用无参数的构造函数 ....}作用:合理利用代码,减少代码重复。通过使用其他构造函数执行初始化过程
#include "iostream"using namespace std;class Clock {public: Clock(int newH, int newM, int newS); //构造函数 Clock(); //默认构造函数 void setTime(int newH, int newM, int newS); void showTime();private: int hour, minute, second;};Clock::Clock(): hour(newH),minute(newM),second(newS) { }Clock::Clock(0,0,0){}//默认构造函数int main() { Clock c1(0, 0, 0); //调用有参数的构造函数 Clock c2; //调用无参数的构造函数 ....}(1)复制构造函数定义
复制构造函数是一种特殊的构造函数,其形参为本类的对象引用。作用是用一个已存在的对象去初始化同类型的新对象。
class类名 {public : 类名(形参);//构造函数 类名(const 类名 &对象名);//复制构造函数 // ...};类名::类(const 类名&对象名)//复制构造函数的实现{ 函数体 }(2)隐含的复制构造函数
如果程序员没有为类声明拷贝初始化构造函数,则编译器自己生成一个隐含的复制构造函数。
这个构造函数执行的功能是:用作为初始值的对象的每个数据成员的值,初始化将要建立的对象的对应数据成员。
(3)如果不希望对象被复制构造
例:
class Point { //Point 类的定义public: Point(int xx=0, int yy=0) { x = xx; y = yy; } //构造函数,内联 Point(const Point& p) =delete; //指示编译器不生成默认复制构造函数private: int x, y; //私有数据};(4)复制构造函数被调用的三种情况
即类中的成员是另一个类的对象。
(1)原则:不仅要负责对本类中的基本类型成员数据初始化,也要对对象成员初始化。
(2)声明形式:
类名::类名(对象成员所需的形参,本类成员形参):对象1(参数),对象2(参数),......{ //函数体其他语句}类应该先声明,后使用;如果需要在某个类的声明之前,引用该类,则应进行前向引用声明;前向引用声明只为程序引入一个标识符,但具体声明在其他地方。
例:
class B; //前向引用声明class A {public: void f(B b); //声明函数,形参定义时不分配内存空间};class B {public: void g(A a);};例:
class Fred; //前向引用声明class Barney { Fred x; //错误,这里是用类定义一个对象,得分配内存。};class Fred { Barney y;};UML中最基础的三个部分:
事物:
关系:联系事物
图:多个有联系的事物






举例:


(1)结构体是一种特殊形态的类
(2)什么时候用结构体而不用类?
struct 结构体名称 { 公有成员 protected: 保护型成员 private: 私有成员};如果一个结构体的全部数据成员都是公共成员,并且没有用户定义的构造函数,没有基类和虚函数,这个结构体的变量可以用下面的语法形式赋初值
类型名 变量名 = { 成员数据1初值, 成员数据2初值, …… };union 联合体名称 { 公有成员protected: 保护型成员private: 私有成员};
union { int i; float f;}在程序中可以这样使用:i = 10;f = 2.2;// 10被覆盖掉了enum class 枚举类型名: 底层类型 {枚举值列表};(1)强作用域,其作用域限制在枚举类中。
例:使用Type的枚举值General:Type::General
(2)转换限制,枚举类对象不可以与整型隐式地互相转换。
(3)可以指定底层类型,默认为int
例:enum class Type: char { General, Light, Medium, Heavy};
#include<iostream>using namespace std;enum class Side{ Right, Left };enum class Thing{ Wrong, Right }; //不冲突int main(){ Side s = Side::Right; Thing w = Thing::Wrong; cout << (s == w) << endl; //编译错误,无法直接比较不同枚举类 return 0;}

(1)类的成员具有类作用域
其范围包括类体和成员函数体
(2)在类作用域以外访问类成员
作用域开始于声明,结束于文件尾


(1)静态生存期
(2)动态生存期
举例:
class A { friend class B;//B是A的友元类public: void display() { cout << x << endl; }private: int x;};class B {public: void set(int i); void display();private: A a;};void B::set(int i) { a.x=i;}void B::display() { a.display();};必须进行初始化,不能被更新。
例:
class A{ public: A(int i,int j) {x=i; y=j;} ... private: int x,y;};A const a(3,4); //a是常对象,不能被更新用const进行修饰的类成员:常数据成员和常函数成员
(1)常成员函数
(2)常数据成员
使用const说明的数据成员。
数组元素不能被更新
类型说明符 const 数组名[大小]...
指向常量的指针
一个工程可以划分为多个源文件:
利用工程来组合各个文件。
例如:
//文件1,类的定义,Point.hclass Point { //类的定义public: //外部接口 Point(int x = 0, int y = 0) : x(x), y(y) { } Point(const Point &p); ~Point() { count--; } int getX() const { return x; } int getY() const { return y; } static void showCount(); //静态函数成员private: //私有数据成员 int x, y; static int count; //静态数据成员};//文件2,类的实现,Point.cpp#include "Point.h"#include <iostream>using namespace std;int Point::count = 0; //使用类名初始化静态数据成员Point::Point(const Point &p) : x(p.x), y(p.y) { count++;}void Point::showCount() { cout << " Object count = " << count << endl;}//文件3,主函数,5_10.cpp#include "Point.h"#include <iostream>using namespace std;int main() { Point a(4, 5); //定义对象a,其构造函数使count增1 cout <<"Point A: "<<a.getX()<<", "<<a.getY(); Point::showCount(); //输出对象个数 Point b(a); //定义对象b,其构造函数回使count增1 cout <<"Point B: "<<b.getX()<<", "<<b.getY(); Point::showCount(); //输出对象个数 return 0;}
使用匿名的命名空间:在匿名命名空间中定义的变量和函数,都不会暴露给其它的编译单元。
namespace { //匿名的命名空间 int n; void f() { n++; } }这里被“namespace { …… }”括起的区域都属于匿名的命名空间。
标准C++类库是一个极为灵活并可扩展的可重用软件模块的集合。标准C++类与组件在逻辑上分为6种类型:
#include 包含指令
将一个源文件嵌入到当前源文件中该点处。#include<文件名>
按标准方式搜索,文件位于C++系统目录的include子目录下#include"文件名"
首先在当前目录中搜索,若没有,再按标准方式搜索。
#define 宏定义指令
定义符号常量,很多情况下已被const定义语句取代。
定义带参数宏,已被内联函数取代。#undef
删除由#define定义的宏,使之不再起作用。
(1)#if 和 #endif
#if 常量表达式 //当“ 常量表达式”非零时编译 程序正文 #endif(2)#else
#if 常量表达式 程序正文1 //当“ 常量表达式”非零时编译#else 程序正文2 //当“ 常量表达式”为零时编译#endif(3)#elif
#if 常量表达式1 程序正文1 //当“ 常量表达式1”非零时编译#elif 常量表达式2 程序正文2 //当“ 常量表达式2”非零时编译#else 程序正文3 //其他情况下编译#endif(4)#ifdef 标识符
#ifdef 标识符 程序段1#else 程序段2#endif如果“标识符”经#defined定义过,且未经undef删除,则编译程序段1;否则编译程序段2。
(5)#ifndef 标识符
#ifndef 标识符 程序段1#else 程序段2#endif如果“标识符”未被定义过,则编译程序段1;否则编译程序段2。
求线段的长度
#include <iostream>#include <cmath>using namespace std;class Point { //Point类定义public: Point(int xx = 0, int yy = 0) { x = xx; y = yy; } Point(Point &p); int getX() { return x; } int getY() { return y; }private: int x, y;};Point::Point(Point &p) { //复制构造函数的实现 x = p.x; y = p.y; cout << "Calling the copy constructor of Point" << endl;}//类的组合class Line { //Line类的定义public: //外部接口 Line(Point xp1, Point xp2); Line(Line &l); double getLen() { return len; }private: //私有数据成员 Point p1, p2; //Point类的对象p1,p2 double len;};//组合类的构造函数Line::Line(Point xp1, Point xp2) : p1(xp1), p2(xp2) { cout << "Calling constructor of Line" << endl; double x = static_cast<double>(p1.getX() - p2.getX()); double y = static_cast<double>(p1.getY() - p2.getY()); len = sqrt(x * x + y * y);}Line::Line (Line &l): p1(l.p1), p2(l.p2) {//组合类的复制构造函数 cout << "Calling the copy constructor of Line" << endl; len = l.len;}//主函数int main() { Point myp1(1, 1), myp2(4, 5); //建立Point类的对象 Line line(myp1, myp2); //建立Line类的对象 Line line2(line); //利用复制构造函数建立一个新对象 cout << "The length of the line is: "; cout << line.getLen() << endl; cout << "The length of the line2 is: "; cout << line2.getLen() << endl; return 0;}#include "iostream"using namespace std;struct Student { //学生信息结构体 int num; //学号 string name; //姓名,字符串对象,将在第6章详细介绍 char sex; //性别 int age; //年龄};int main() { Student stu = { 97001, "Lin Lin", 'F', 19 }; cout << "Num: " << stu.num << endl; cout << "Name: " << stu.name << endl; cout << "Sex: " << stu.sex << endl; cout << "Age: " << stu.age << endl; return 0;}使用联合体保存成绩信息,并且输出。
#include <iostream>using namespace std;class ExamInfo {private: string name; //课程名称 enum { GRADE, PASS, PERCENTAGE } mode;//计分方式 union { char grade; //等级制的成绩 bool pass; //只记是否通过课程的成绩 int percent; //百分制的成绩 };public: //三种构造函数,分别用等级、是否通过和百分初始化 ExamInfo(string name, char grade) : name(name), mode(GRADE), grade(grade) { } ExamInfo(string name, bool pass) : name(name), mode(PASS), pass(pass) { } ExamInfo(string name, int percent) : name(name), mode(PERCENTAGE), percent(percent) { } void show();};void ExamInfo::show() { cout << name << ": "; switch (mode) { case GRADE: cout << grade; break; case PASS: cout << (pass ? "PASS" : "FAIL"); break; case PERCENTAGE: cout << percent; break; } cout << endl;}int main() { ExamInfo course1("English", 'B'); ExamInfo course2("Calculus", true); ExamInfo course3("C++ Programming", 85); course1.show(); course2.show(); course3.show(); return 0;}#include <iostream>using namespace std;enum CPU_Rank {P1=1,P2,P3,P4,P5,P6,P7};class CPU{private: CPU_Rank rank; int frequency; float voltage;public: CPU (CPU_Rank r, int f, float v) { rank = r; frequency = f; voltage = v; cout << "构造了一个CPU!" << endl; } //复制(拷贝)构造函数 CPU(CPU &c) { rank= c.rank; frequency = c.frequency; voltage = c.voltage; cout << "拷贝构造了一个CPU!" << endl; } ~CPU () { cout << "析构了一个CPU!" << endl; } CPU_Rank GetRank() const { return rank; } int GetFrequency() const { return frequency; } float GetVoltage() const { return voltage; } void SetRank(CPU_Rank r) { rank = r; } void SetFrequency(int f) { frequency = f; } void SetVoltage(float v) { voltage = v; } void Run() {cout << "CPU开始运行!" << endl; } void Stop() {cout << "CPU停止运行!" << endl; }};enum RAM_Type {DDR2=2,DDR3,DDR4};class RAM{private: enum RAM_Type type; unsigned int frequency;//MHz unsigned int size;//GBpublic: RAM (RAM_Type t, unsigned int f, unsigned int s) { type = t; frequency = f; size = s; cout << "构造了一个RAM!" << endl; } //复制(拷贝)构造函数 RAM(RAM &c) { type= c.type; frequency = c.frequency; size = c.size; cout << "拷贝构造了一个RAM!" << endl; } ~RAM () { cout << "析构了一个RAM!" << endl; } RAM_Type GetType() const { return type; } unsigned int GetFrequency() const { return frequency; } unsigned int GetSize() const { return size; } void SetType(RAM_Type t) { type = t; } void SetFrequency(unsigned int f) { frequency = f; } void SetSize(unsigned int s) { size = s; } void Run() {cout << "RAM开始运行!" << endl; } void Stop() {cout << "RAM停止运行!" << endl; }};enum CDROM_Interface {SATA,USB};enum CDROM_Install_type {external,built_in};class CD_ROM{private: enum CDROM_Interface interface_type; unsigned int cache_size;//MB CDROM_Install_type install_type;public: CD_ROM (CDROM_Interface i, unsigned int s, CDROM_Install_type it) { interface_type = i; cache_size = s; install_type = it; cout << "构造了一个CD_ROM!" << endl; } ~CD_ROM () { cout << "析构了一个CD_ROM!" << endl; } //复制(拷贝)构造函数 CD_ROM(CD_ROM &c) { interface_type= c.interface_type; cache_size = c.cache_size; install_type = c.install_type; cout << "拷贝构造了一个CD_ROM!" << endl; } CDROM_Interface GetInterfaceType() const { return interface_type; } unsigned int GetSize() const { return cache_size; } CDROM_Install_type GetInstallType() const { return install_type; } void SetInterfaceType(CDROM_Interface i) { interface_type = i; } void SetSize(unsigned int s) { cache_size = s; } void SetInstallType(CDROM_Install_type it) { install_type = it; } void Run() {cout << "CD_ROM开始运行!" << endl; } void Stop() {cout << "CD_ROM停止运行!" << endl; }};class COMPUTER{private: CPU my_cpu; RAM my_ram; CD_ROM my_cdrom; unsigned int storage_size;//GB unsigned int bandwidth;//MBpublic: COMPUTER (CPU c, RAM r, CD_ROM cd,unsigned int s,unsigned int b); ~COMPUTER () { cout << "析构了一个COMPUTER!" << endl; } void Run() { my_cpu.Run(); my_ram.Run(); my_cdrom.Run(); cout << "COMPUTER开始运行!" << endl; } void Stop() { my_cpu.Stop(); my_ram.Stop(); my_cdrom.Stop(); cout << "COMPUTER停止运行!" << endl; }};COMPUTER::COMPUTER(CPU c, RAM r, CD_ROM cd,unsigned int s,unsigned int b): my_cpu(c),my_ram(r),my_cdrom(cd){ storage_size = s; bandwidth = b; cout << "构造了一个COMPUTER!" << endl;}int main(){ CPU a(P6,300,2.8); a.Run(); a.Stop(); cout<<"*************************\n"; RAM b(DDR3,1600,8); b.Run(); b.Stop(); cout<<"*************************\n"; CD_ROM c(SATA,2,built_in); c.Run(); c.Stop(); cout<<"*************************\n"; COMPUTER my_computer(a,b,c,128,10); cout<<"*************************\n"; my_computer.Run(); my_computer.Stop(); cout<<"*************************\n"; return 0;}输出:构造了一个CPU!CPU开始运行!CPU停止运行!*************************构造了一个RAM!RAM开始运行!RAM停止运行!*************************构造了一个CD_ROM!CD_ROM开始运行!CD_ROM停止运行!*************************拷贝构造了一个CPU!拷贝构造了一个RAM!拷贝构造了一个CD_ROM!拷贝构造了一个CPU!拷贝构造了一个RAM!拷贝构造了一个CD_ROM!构造了一个COMPUTER!析构了一个CD_ROM!析构了一个RAM!析构了一个CPU!*************************CPU开始运行!RAM开始运行!CD_ROM开始运行!COMPUTER开始运行!CPU停止运行!RAM停止运行!CD_ROM停止运行!COMPUTER停止运行!*************************析构了一个COMPUTER!析构了一个CD_ROM!析构了一个RAM!析构了一个CPU!析构了一个CD_ROM!析构了一个RAM!析构了一个CPU!#include<iostream>using namespace std;int i = 1; // i 为全局变量,具有静态生存期。void other(){ static int a = 2; static int b; // a,b为静态局部变量,具有全局寿命,局部可见。 //只第一次进入函数时被初始化 int c = 10; // C为局部变量,具有动态生存期, //每次进入函数时都初始化。 a += 2; i += 32; c +=5; cout<<"---OTHER---\n"; cout<<" i: "<<i<<" a: "<<a<<" b: "<<b<<" c: "<<c<<endl; b = a;}int main() { static int a;//静态局部变量,有全局寿命,局部可见。 int b = -10; // b, c为局部变量,具有动态生存期。 int c = 0; cout << "---MAIN---\n"; cout<<" i: "<<i<<" a: "<<a<<" b: "<<b<<" c: "<<c<<endl; c += 8; other(); cout<<"---MAIN---\n"; cout<<" i: "<<i<<" a: "<<a<<" b: "<<b<<" c: "<<c<<endl; i += 10; other(); return 0;}输出:---MAIN--- i: 1 a: 0 b: -10 c: 0---OTHER--- i: 33 a: 4 b: 0 c: 15---MAIN--- i: 33 a: 0 b: -10 c: 8---OTHER--- i: 75 a: 6 b: 4 c: 15#include <iostream>using namespace std;class Point { //Point类定义public: //外部接口 Point(int x = 0, int y = 0) : x(x), y(y) { //构造函数 //在构造函数中对count累加,所有对象共同维护同一个count count++; } Point(Point &p) { //复制构造函数 x = p.x; y = p.y; count++; } ~Point() { count--; } int getX() { return x; } int getY() { return y; } void showCount() { //输出静态数据成员 cout << " Object count = " << count << endl; }private: //私有数据成员 int x, y; static int count; //静态数据成员声明,用于记录点的个数};int Point::count = 0;//静态数据成员定义和初始化,使用类名限定int main() { //主函数 Point a(4, 5); //定义对象a,其构造函数回使count增1 cout << "Point A: " << a.getX() << ", " << a.getY(); a.showCount(); //输出对象个数 Point b(a); //定义对象b,其构造函数回使count增1 cout << "Point B: " << b.getX() << ", " << b.getY(); b.showCount(); //输出对象个数 return 0;}输出:Point A: 4, 5 Object count = 1Point B: 4, 5 Object count = 2#include <iostream>using namespace std;class Point { //Point类定义public: //外部接口 Point(int x = 0, int y = 0) : x(x), y(y) { //构造函数 //在构造函数中对count累加,所有对象共同维护同一个count count++; } Point(Point &p) { //复制构造函数 x = p.x; y = p.y; count++; } ~Point() { count--; } int getX() { return x; } int getY() { return y; } static void showCount() { //输出静态数据成员 cout << " Object count = " << count << endl; }private: //私有数据成员 int x, y; static int count; //静态数据成员声明,用于记录点的个数};int Point::count = 0;//静态数据成员定义和初始化,使用类名限定int main() { //主函数 Point::showCount(); Point a(4, 5); //定义对象a,其构造函数回使count增1 cout << "Point A: " << a.getX() << ", " << a.getY(); a.showCount(); //输出对象个数 Point b(a); //定义对象b,其构造函数回使count增1 cout << "Point B: " << b.getX() << ", " << b.getY(); b.showCount(); //输出对象个数 return 0;}输出: Object count = 0Point A: 4, 5 Object count = 1Point B: 4, 5 Object count = 2使用友元函数计算两点间的距离
#include <iostream>#include <cmath>using namespace std;class Point { //Point类声明public: //外部接口 Point(int x=0, int y=0) : x(x), y(y) { } int getX() { return x; } int getY() { return y; } friend float dist(Point &a, Point &b);//友元函数,访问类的私有数据private: //私有数据成员 int x, y;};float dist( Point& a, Point& b) { double x = a.x - b.x; double y = a.y - b.y; return static_cast<float>(sqrt(x * x + y * y));}int main() { Point p1(1, 1), p2(4, 5); cout <<"The distance is: "; cout << dist(p1, p2) << endl; return 0;}输出:The distance is: 5#include<iostream>using namespace std;class R {public: R(int r1, int r2) : r1(r1), r2(r2) { } void print(); void print() const;private: int r1, r2;};void R::print() { cout << r1 << ":" << r2 << endl;}void R::print() const { cout << r1 << ";" << r2 << endl;}int main() { R a(5,4); a.print(); //调用void print() const R b(20,52); b.print(); //调用void print() const return 0;}输出:5:420;52#include <iostream>using namespace std;class A {public: A(int i); void print();private: const int a; static const int b; //静态常数据成员};const int A::b=10;A::A(int i) : a(i) //只能在此赋值{ }void A::print() { cout << a << ":" << b <<endl;}int main() {//建立对象a和b,并以100和0作为初值,分别调用构造函数,//通过构造函数的初始化列表给对象的常数据成员赋初值 A a1(100), a2(0); a1.print(); a2.print(); return 0;}输出:100:100:10#include <iostream>#include <cmath>using namespace std;class Point { //Point类定义public: //外部接口 Point(int x = 0, int y = 0): x(x), y(y) { } int getX() { return x; } int getY() { return y; } friend float dist(const Point &p1,const Point &p2);private: //私有数据成员 int x, y;};//const Point &p1, const Point &p2:常引用,不改变引用对象值float dist(const Point &p1, const Point &p2) { double x = p1.x - p2.x; double y = p1.y - p2.y; return static_cast<float>(sqrt(x*x+y*y));}int main() { //主函 const Point myp1(1, 1), myp2(4, 5); cout << "The distance is: "; cout << dist(myp1, myp2) << endl; return 0;}输出:The distance is: 5
/* client.h*///防止重复包含头文件#ifndef CLIENT_H_#define CLIENT_H_class Client { static char ServerName; static int ClientNum;public: static void ChangeServerName(char name); static int getClientNum();};#endif //CLIENT_H_/* client.cpp*/#include "client.h"void Client::ChangeServerName(char name) { Client::ServerName = name; Client::ClientNum ++;}int Client::getClientNum() { return Client::ClientNum;}/* test.h*/#include <iostream>#include "client.h"using namespace std;int Client::ClientNum = 0;char Client::ServerName = 'a';int main(){ Client c1; c1.ChangeServerName('a'); cout << c1.getClientNum() << endl; Client c2; c2.ChangeServerName('b'); cout << c2.getClientNum() << endl; return 0;}(1)抽象使得协同工作的开发人员可以更多地关注他人的代码功能而非代码实现。
对
(2)在C++中,编译系统自动为一个类生成缺省构造函数的条件是
(3)以下关于结构体和联合体说法正确的是
(4)静态函数不可直接访问对象的变量
对
(5)以下关于外部变量和外部函数的说法,错误的是
分析:
使用外部变量时,需要使用extern;使用外部函数时,要么使用extern,要么重新声明函数原型
(6)以下关于预处理的说法,错误的是
分析:预处理指令无需结尾分号