C++教程(2) 面向对象编程

函数

定义和声明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include<iostream>
int add(int, int); //声明函数
int main(){
int a = 6, b = 9;
int c = add(a, b);
std::cout << c << std::endl;
getchar();
return 0;
}
//定义函数
int add(int a , int b)
{
int c = a + b;
return c;
}

函数参数

1
2
3
4
5
6
7
8
int func(int val) //副本传递
//副本传递时,修改val不影响原来的val值

int func(int &val) //引用传递
int func(int *val) //指针传递
//指针和引用传递时,修改val会影响原来的val值

int func(int a, int b, int args ...);//可变参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#实例 数字交换
#include<iostream>
void func1(int, int);
void func2(int &, int &);
void func3(int *, int *);
int main(){
int a = 6, b = 9;
func1(a, b);
std::cout << "func1 ----> a:" << a << " b:"<< b << std::endl; //a,b未交换
func2(a, b);
std::cout << "func2 ----> a:" << a << " b:" << b << std::endl; //a,b被交换
func3(&a, &b);
std::cout << "func3 ----> a:" << a << " b:" << b << std::endl;//a,b被交换
getchar();
return 0;
}
void func1(int a , int b){
int temp = 0;
temp = a;
a = b;
b = temp;
}
void func2(int &a, int &b) {
int temp = 0;
temp = a;
a = b;
b = temp;
}
void func3(int *a, int *b) {
int *temp = 0;
temp = a;
a = b;
b = temp;
}
结果:
func1 ----> a:6 b:9
func2 ----> a:9 b:6
func3 ----> a:9 b:6

函数地址作为函数参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include<iostream>
void swap(int &, int &);
void func1(int &, int &, void(*pf)(int &, int &));
int main(){
int a = 6, b = 9;
void(*pf)(int &, int &);
pf = swap;
(*pf)(a,b);
std::cout << "a:" << a << " b:" << b << std::endl; //a,b被交换

int c = 17, d = 29;
func1(c,d,pf);
std::cout << "c:" << c << " d:" << d << std::endl; // c,d被交换
getchar();
return 0;
}

void func1(int &c,int &d,void (*pf)(int &,int &)) {
(*pf)(c,d);
}
void swap(int &a, int &b) {
int temp = 0;
temp = a;
a = b;
b = temp;
}
结果:
a:9 b:6
c:29 d:17

内联函数

常规函数的调用过程
程序执行到”函数指令”代码处时,立即存储”函数指令”代码的内存地址,并将函数参数复制到堆栈,然后跳到函数起点的内存单元((函数的内存地址,非”函数指令”代码地址)执行函数代码,函数执行结束后跳回保存的”函数指令”内存地址处,即跳回到程序执行函数指令的那一行,然后继续执行余下的指令.
内联函数调用过程
程序执行到”函数指令”代码处时,编译器将调用的函数代码替换掉该函数指令,无需再跳转到函数的位置去执行.速度比常规函数调用快,但内存开销大,假设程序有10个地方条用了同一个内联函数,则程序中将包含该内联函数代码的10个副本.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
using namespace std;
inline int Max(int x, int y){
return (x > y) ? x : y;
}
int main(){
std::cout << "Max (20,10):" << Max(20, 10) << std::endl;
std::cout << "Max (0,200): " << Max(0, 200) << std::endl;
std::cout << "Max(100,1010): " << Max(100, 1010) << std::endl;
return 0;
}

结果:
Max (20,10): 20
Max (0,200): 200
Max (100,1010): 1010

函数默认参数

带默认参数的函数 必须从右至左添加默认值

1
2
3
4
5
void func(int a,int b,double c = 3.14); //合法
void func(int a,int b = 2,double c); //非法
#调用时具有默认参数的参数可选
func(1,2);
func(1,2,3);

类和对象

声明和定义

person.h 声明类person的头文件
若在类中声明函数暨定义,则函数当作内联函数处理

1
2
3
4
5
6
7
8
9
10
11
12
#include<string>
class person {
public:
person();
person(std::string name);
std::string print_info(std::string name,int year);
void print_name();
void print();
int add(int a,int b){return a + b}//当作内联函数处理
private:
std::string name;
};

person.cpp 定义类person中的函数和变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include "person.h"
#include<iostream>
#include<string>
person::person(){};
person::person(std::string name){
person::name = name;
}

std::string person::print_info(std::string name, int year){
std::cout << "your name is " << name << " and your age is " << year << std::endl;
return "hi " + name;
}

void person::print_name(){
std::cout << person::name << std::endl;
}

void person::print(){
std::cout << "hello person " << std::endl;
}

main.cpp 使用person类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include<iostream>
#include<string>
#include "person.h"
int main(){
person p1;
p1.print();

person p2("kyleson");
p2.print_name();
std::string info = p2.print_info("kyleson",19);
std::cout << info << std::endl;
getchar();
return 0;
}
结果:
hello person
kyleson
your name is kyleson and your age is 19
hi kyleson

常量成员函数

Date类中的成员函数(+const)表示函数为只读函数,不能对类Date的成员和状态进行修改

1
2
3
4
5
6
7
8
9
class Date {
int d, m, y;
public:
int day() const { return d; }
int month() const;
};
int Date::month() const {
return Date::m;
}

mutable成员

mutable修饰的成员仍可被常量成员函数修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Date {
int d, m, y;
public:
int day() const { return d; }
int month() const;
private:
int century;
mutable int cache;
};

int Date::month() const {
Date::century = 0;//错误,month()函数不可修改century的值
Date::cache = 0;
return Date::m;
}

自引用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Date {
int d = 12, m = 6, y =2018;
public:
Date& add_day(){ d++; };
Date& add_month(){ m++; };
Date& add_year() { y++; };
private:
int cache;
mutable int modied;
};

int main(){
Date date;
date.add_year().add_month().add_day();
getchar();
return 0;
}

析构函数

类的析构函数是类的一种特殊的成员函数,在每次删除所创建的对象时执行
析构函数的名称与类的名称完全相同,由波浪号(~)作为其前缀,析构函数不会返回任何值,也不能带有任何参数.析构函数有助于在跳出程序(比如关闭文件、释放内存等)前释放资源.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
using namespace std;
class Line{
public:
Line(); // 构造函数声明
~Line(); // 析构函数声明
};
Line::Line(void){
cout << "Object is being created" << endl;
}
Line::~Line(void){
cout << "Object is being deleted" << endl;
}
// 程序的主函数
int main(){
Line line;
return 0;
}
结果:
Object is being created
Object is being deleted

友元函数

访问类的 private 和 protected 成员

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
using namespace std;
class Box{
double width;
public:
friend void printWidth(Box box);
void setWidth(double wid);
};
void Box::setWidth(double wid){
width = wid;
}
//注意:printWidth() 不是任何类的成员函数
void printWidth(Box box){
cout << "Width of box : " << box.width << endl;
}
int main(){
Box box;
box.setWidth(10.0);
printWidth(box);
return 0;
}

this 指针

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
using namespace std;
class Box{
public:
Box(double length = 2.0){
length = length;
}
int compare(Box box){
return this-> length > box. length;
}
private:
double length;
};
int main(void){
Box Box1(3.3);
Box Box2(8.5);
if(Box1.compare(Box2)){
cout << "Box2 is smaller than Box1" << endl;
}else{
cout << "Box2 is equal to or larger than Box1" << endl;
}
return 0;
}

指向类的指针

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
using namespace std;
class Box{
public:
Box(double h = 2.0){
height = h;
}
double Volume(){
return length * breadth *height;
}
private:
double height;
};
int main(void){
Box Box1(3.3);
Box *ptrBox;
ptrBox = &Box1;
cout << "Volume of Box1: " << ptrBox->Volume() << endl;
return 0;
}

类的静态成员

静态成员在类的所有对象中是共享的, 无论创建多少个类的对象,静态成员都只有一个副本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Box{
public:
static int objectCount;
Box(double h = 2.0){
height = h;
objectCount++;
}
double Volume(){
return length * breadth *height;
}
private:
double height;
};
int Box::objectCount = 0;
int main(void){
Box Box1(3.3);
Box Box2(8.5);
cout << "Total objects: " << Box::objectCount << endl; //objectCount = 2
return 0;
}

继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>
using namespace std;
// 基类
class Shape {
public:
void setWidth(int w) {
width = w;
}
void setHeight(int h) {
height = h;
}
protected:
int width;
int height;
};
// 派生类
class Rectangle : public Shape {
public:
int getArea() {
return (width * height);
}
};

int main(void) {
Rectangle Rect;
Rect.setWidth(5);
Rect.setHeight(7);
cout << "Total area:" << Rect.getArea() << endl;
getchar();
return 0;
}

多继承

1
2
3
4
5
// 基类
class Shape {...};
class PaintCost {...};
// 多继承
class Rectangle : public Shape, public PaintCost {...};

虚函数和纯虚函数 virtual 修饰符

类中被声明为虚函数的函数在基类中实现也可被派生类重写.
类中被声明为纯虚函数的函数在基类中只能声明,定义纯虚函数是为定义一个接口,必须由派生类实现,且这个类是抽象类,包含纯虚函数的类不能创建对象,只能作为基类.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Shape {
//虚函数
virtual int area(){
cout << "Parent class area :" << endl;
return 0;
}
};
class Rectangle : public Shape {
//重写的虚函数
int area(){
cout << "Rectangle class area :" << endl;
return (width * height);
}
};

class Shape {
//纯虚函数 由派生类实现
virtual int area() = 0;
};

多态

多个派生类根据需要对基类的虚函数进行了不同的实现,在函数调用时会根据派生类的不同进行相应的调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream> 
using namespace std;
class Shape {
public:
virtual void area() {
cout << "Parent class area :" << endl;
}
};
class Rectangle : public Shape {
public:
void area() {
cout << "Rectangle class area " << endl;
}
};
class Triangle : public Shape {
public:
void area() {
cout << "Triangle class area " << endl;
}
};
int main() {
Shape *shape;
Rectangle rec;
Triangle tri;
shape = &rec;
shape->area();
shape = &tri;
shape->area();
getchar();
return 0;
}
结果:
Rectangle class area
Triangle class area

运算符重载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Date {
public:
int d = 12, m = 6, y = 2018;
Date operator+(const Date &a);
void operator++();
};
Date Date::operator+(const Date & a){
Date c;
c.d = this->d + a.d;
c.m = this->m + a.m;
c.y = this->y + a.y;
return c;
}
void Date::operator++(){
this->y++;
this->m++;
this->d++;
}

int main(){
Date a,b;
Date c = a + b;
std::cout << c.y << std::endl;
Date d;
++d;//++d == d.operator++();
std::cout << d.y;
getchar();
return 0;
}

异常处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
//捕获并处理异常
void task_master(){
try{
auto result = do_task();
}catch(some_error){
//todo
}
}
//抛出异常
int do_task(){
if(...)
return result;
else
throw some_error{};
}

#include <iostream>
using namespace std;

double division(int a, int b){
if( b == 0 ){
throw "Division by zero condition!";
}
return (a/b);
}

int main (){
int x = 50;
int y = 0;
double z = 0;

try {
z = division(x, y);
cout << z << endl;
}catch (const char* msg) {
cerr << msg << endl;
}

return 0;
}

C++标准异常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <exception>
using namespace std;

struct MyException : public exception{
const char * what() const throw (){
return "C++ Exception";
}
};

int main(){
try{
throw MyException();
}catch(MyException& e){
std::cout << "MyException caught" << std::endl;
std::cout << e.what() << std::endl;
}catch(std::exception& e){
//其他的错误
}
}

文件输入输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <fstream>
#include <iostream>
#include <string>
#include <cstdlib>

int main() {
std::ifstream fin;
fin.open("test.txt");
if(fin.is_open() == false){
std::cerr << "cant not open the file \n";
std::exit(EXIT_FAILURE);
}
std::string item;
getline(fin,item);
while (fin){
std::cout << item << "\n";
getline(fin,item);
}
std::cout << "done" << "\n";
fin.close();
return 0;
}

C++教程(2) 面向对象编程
https://jiaopaner.github.io/2019/07/05/C++教程(2) 面向对象编程/
作者
JiaoPan
发布于
2019年7月5日
许可协议