<<从0到1学C++>> 第3篇 从结构到类的演变

栏目: C++ · 发布时间: 7年前

内容简介:C++中的类是从结构演变而来的, 所以我们可以称C++为”带类的C”.C++结构中可以定义函数, 称之为成员函数

本篇要学习的内容和知识结构概览

<<从0到1学C++>> 第3篇 从结构到类的演变

知识点逐条分析

结构的演化

C++中的类是从结构演变而来的, 所以我们可以称C++为”带类的C”.

结构发生质的演变

C++结构中可以定义函数, 称之为成员函数

结构定义格式, 像这样:

struct 结构名 {

数据成员;

成员函数;

}; // 注意这里的分号不要忘记

具体的代码, 像这样:

struct Point {
    private:
        // 数据成员
        double x;
        double y;
        
    public:
        // 成员函数: 重新设置数据成员
        void setXY(double a, double b) {
            x = a;
            y = b;
        }
        
        // 成员函数: 指定格式输出数据成员
        void display() {
            cout << x << "\t" << y << endl;
        }
}; // 不要忘记分号复制代码

模型图是这样的:

<<从0到1学C++>> 第3篇 从结构到类的演变

它表明: 我定义了一个结构体, 有两个私有的数据成员x, y, 两个公有的成员函数setXY(double, x, double y), display();

在定义结构体时, 将数据成员使用private关键字修饰, 则产生封装性. 如果没有没定, 则默认为public

private修饰的数据成员为私有的数据成员, 必须公有的成员函数才能使用, 这就是数据的封装性.

使用方式: 结构对象.成员函数

我们在main函数中这样使用:

// 创建结构对象
Point pointA;

// 调用成员函数
pointA.setXY(1.2, 3.4);

// 显示pointA的数据成员
pointA.display();
复制代码

注意: 

如果结构的数据成员用private关键字修饰

则不能这么访问:

cout << pointA.x << endl; count << pointA.y << endl;

如果public修饰, 则可以这么访问.

不过我们一般为了保证封装性, 将数据成员声明为private, 保证只有成员函数才能访问.

使用构造函数初始化结构对象

函数名与结构同名, 称为构造函数, 专门用于初始化结构对象

分为有参构造函数和无参构造函数

像这样:

#include <iostream>
using namespace std;

struct Point {
    private:
        // 数据成员
        double x;
        double y;
        
    public:
        // 无参构造函数
        Point(){}
        
        // 有参构造函数
        Point(double a, double b) {
            x = a;
            y = b;
        }
        
        // 成员函数: 重新设置数据成员
        void setXY(double a, double b) {
            x = a;
            y = b;
        }
        
        // 成员函数: 指定格式输出数据成员
        void display() {
            cout << x << "\t" << y << endl;
        }
    };复制代码
int main(int argc, const char * argv[]) {
    // insert code here...
   
    // 使用构造函数创建结构对象pointA
    Point pointA(20, 30);
    
    // 显示pointA的数据成员
    pointA.display();
    return 0;
}复制代码

模型图是这样的:

<<从0到1学C++>> 第3篇 从结构到类的演变

它表明: 我定义了一个结构体, 有两个私有的数据成员x, y, 一个无参构造函数Point(), 一个有参构造函数Point(double x, double y), 两个普通的成员函数setXY(double, x, double y), display();

从结构演变成一个简单的类

使用关键字class代替stuct, 就将一个结构演变成一个标准的类啦! 是不是So easy!

像这样:

class Point { // 这里struct 变成 class, 就完成了从结构到类的演变
	private:
	    // 数据成员
	    double x;
	    double y;
	
	public:
	    // 无参构造函数
	    Point(){}
	
	    // 有参构造函数
	    Point(double a, double b) {
	        x = a;
	        y = b;
	    }
	
	    // 成员函数: 重新设置数据成员
	    void setXY(double a, double b) {
	        x = a;
	        y = b;
	    }
	
	    // 成员函数: 指定格式输出数据成员
	    void display() {
	        cout << x << "\t" << y << endl;
	    }
};复制代码

好的, 从现在开始把我们的目光从struct移开吧, 让我们聚焦于class!

面向过程与面向对象

编程语言是我们和计算机交流的桥梁, 编程技术在发展, 同样的编程语言也在发展, 编程语言从最初的0和1, 到汇编语言, 再到面向过程的语言, 再到面向对象的语言, 反应出了我们的编程思想也在不断的进步, 面向过程只是关注解决问题的步骤, 而面向对象关注解决问题的对象, 也就是谁解决这个问题.

下面我用两个经典的例子来诠释面向过程和面向对象的区别

第一个: 五子棋游戏

面向过程是这样的:

(1)开始游戏 -> (2)黑子下棋 -> (3)绘制画面 -> (4)判断输赢 -> (5)白子下棋 -> (6)绘制画面 -> (7)判断输赢 -> (8)返回步骤(2)

面向对象是这样的:

黑白双方, 负责下棋这个操作

棋盘系统, 负责绘制画面

规则系统, 负责判断是否犯规, 输赢等

第二个: 把大象装进冰箱

面向过程是这样的:

(1)把冰箱门打开 -> (2)把大象装进去 -> (3)把冰箱门关上

面向对象是这样的:

冰箱 -> 开门

冰箱 -> 装大象

冰箱 -> 关门

冰箱是一个对象, 它有开门的操作, 装大象的操作, 关门的操作, 大象也是一个对象

总结

面向过程就是关注解决问题的步骤, 像这样: 第一步打开冰箱门, 第二步装大象, 第三步关闭冰箱门

面向对象就是关注解决问题的对象, 像冰箱, 它有开门的方法, 装大象的方法, 关门的方法

大家知道基本的区别和联系就可以啦. 也可以找我细聊哦!

面向对象程序设计的特点

面向对象的程序设计具有抽象, 封装, 继承和多态性的特点

对象

对象是系统描述客观事物的一个实体, 是构成系统的基本单位

对象用对象名, 属性(数据成员), 操作(功能函数)三要素来描述

对象名: 用来标识一个具体的对象. 如: zhangsan, lisi等

属性: 这个对象的数据成员, 也就是特征, 如: 姓名, 年龄, 性别等

操作: 这个对象所具有的行为, 如: 吃饭, 睡觉, 打豆豆等

像这样:

我们有一个对象

对象名: zhangsan

数据成员: 姓名叫张三, 年龄18岁

成员函数: 会吃饭, 能睡觉, 还喜欢打豆豆

<<从0到1学C++>> 第3篇 从结构到类的演变

抽象和类

比如我们还有一个学生对象叫李四

<<从0到1学C++>> 第3篇 从结构到类的演变

我们现在有两个学生对象一个叫张三, 年龄18, 一个叫李四, 年龄20, 比如我们还有一个学生对象叫王五, 年龄22, 假如我们还有好多个学生.

都有姓名, 年龄的基本属性, 也有吃饭, 睡觉, 打豆豆的行为,

我们把这些对象的共同特征进一步抽象出来, 就形成了类的概念

像这样:

<<从0到1学C++>> 第3篇 从结构到类的演变

这是一个类,

类名: Student

数据成员: name, age

成员函数: eat(), sleep(), dadoudou()

我们用代码表示是这样的:

// 定义学生类
class Student {
    private:
    
    // 姓名
    string name;
    
    // 年龄
    int age;
    
    public:
    
    // 构造方法
    Student(string aName, int anAge) {
        name = aName;
        age = anAge;
    }
    
    // 吃饭
    void eat() {
        cout << name << "吃饭" << endl;
    }
    
    // 睡觉
    void sleep() {
        cout << name << "睡觉" << endl;
    }
    
    // 打豆豆
    void dadoudou() {
        cout << name << "打豆豆" << endl;
    }
};

int main(int argc, const char * argv[]) {
    // insert code here...
    
    // 使用构造方法创建学生对象,
    Student zhangsan("张三", 18);
    
    // 对象方法
    zhangsan.eat();
    zhangsan.sleep();
    zhangsan.dadoudou();

    // 还可以继续创建其它学生对象, 比如李四, 王五, 赵六等
    return 0;
}复制代码

类和对象的关系

类相当于模具

对象相当于用模具所制造出来的东西

类是具有相同的属性和操作的一组对象的集合

对象是这些集合当中的一个个体

这样理解:

李四是一个学生 // 正确, 因为李四是对象, 而学生是类

学生就是李四 // 错误, 学生是一个群体, 怎么可能是单个个体呢

封装

一个经典的例子来加深我们的理解吧!

电视机把各种部件都装在机箱里, 遥控器的所有部件也都装在遥控器里, 我们通过遥控器操作电视机, 而不是我们自己摆弄电视机的各个组件! 比如音量+, 音量-, 而不是咱们去电视机里摆弄线圈!

封装性就是要求一个对象应该具备明确的功能, 并具有接口以便和其它对象相互作用, 对象内部的数据和代码是受保护的, 外界不能访问它们, 只能对象对外提供的接口可以访问它们. 增加独立, 自己的数据只能由自己来操作.

类的封装是通过定义的存取权限实现的, 分为private和public, 对象的外部只能访问对象的公有部分, 也就是public修饰的, 不能访问对象的私有部分, 也就是private修饰的.

继承

继承是一个类可以获得另一个类的特性的机制

像这样:

<<从0到1学C++>> 第3篇 从结构到类的演变

比如我们有”人”这个类, 它具有姓名, 年龄这两个属性, 吃饭这个行为

我们又有”老师”这个类, 继承自”人”类, 所以它有继承过来的"姓名", "年龄"属性, 还有自己所独有的"职工编号"属性, 有继承过来的"吃饭"行为, 还有自己所独有的"讲课"行为.

我们又有”学生”这个类, 继承自”人”类, 所以它有继承过来的"姓名", "年龄"属性, 还有自己所独有的"学号"属性, 有继承过来的"吃饭"行为, 还有自己所独有的"听课"行为.

总结

子类只需定义它所特有的特征, 而共享父类的特征

多态性

不同的对象可以调用相同名称的函数, 但可导致完全不同的行为的现象称为多态性.

在C++中, 多态性分为两种, 一种称为编译时多态, 另一种为运行时多态

编译时多态

也就是函数重载. 是指同一个函数名可以对应着多个函数的实现, 具体调用哪个函数由参数个数, 参数类型等来决定

运行时多态

也就是虚函数. 在定义了虚函数后, 可以在基类的派生类中对虚函数重新定义, 以实现所想要的功能

使用类和对象

使用string对象

必须包含该类的头文件, #include <string>

像这样:

String str = “RayLee”; // 等价于 String str(“RayLee”);
复制代码

在字符串的末尾系统会加上’’\0”字符来表示字符串的结束, 但是在计算字符串长度的时候不包含'\0'

像这样:

<<从0到1学C++>> 第3篇 从结构到类的演变

String str2 = ‘A’; // 错误, str2是字符串对象, 不能赋值为字符

我们可以把字符串看成是字符数组

所以我们可以这么使用

// 字符串对象
string str = "RayLee";

// 输出字符串中的每个字符, 其中size()为string对象的成员函数, 返回字符串长度
for (int i = 0; i < str.size(); i++) {
    cout << str[i] << endl;
}
复制代码

字符串连接符号 +

作用: 将两个字符串或者字符串与字符拼接起来

像这样:

// 两个字符串拼接
string str = "RayLee";
string str2 = " is a student!";
string str3 = str + str2;
cout << str3 << endl;

// 字符串跟字符拼接
str3 = str + '!';
cout << str3 << endl;

// 现个字符相拼接是不行的
str3 = 'a' + '?'; // 错误, 这样的话就不是拼接了, 就是加法运算啦复制代码

使用string类的典型成员函数

string str = "Hello, World!";
cout << str << endl;

// size()函数: 给定字符串的长度
unsigned long size = str.size();
cout << "字符串长度: " << size << endl;

// find(要查找的字符串, 开始查找的起始位置)函数: 要查找的字符串在给定字符串的起始位置
unsigned long result = str.find("lll");
if (result >= size) {
    cout << "没有查找到该字符串" << endl;
} else {
    cout << "字符串起始位置为: " << result << endl;
}

// substr(起始位置, 截取长度)函数: 给定字符串的子串
string subStr = str.substr(2, 8);
cout << "截取的字符串: " <<  subStr << endl;

// getline()函数: 从cin对象中读出一行给string对象
string inputStr;
getline(cin, inputStr, '\n');
cout << inputStr << endl;

// swap()交换函数: 将两个string对象的内容进行交换
string str1 = "I am a student!";
string str2 = "You are a teacher!";
cout << "交换前: " << str1 << " " << str2 << endl;
str1.swap(str2);
cout << "交换后: " << str1 << " " << str2 << endl;复制代码

面向过程和面向对象不是对立的, 面向对象是建立在面向过程的基础上的, 它们是相互依存的, 面向过程关注于解决问题的步骤, 而面向对象关注于解决问题中出现的对象, 而对象中则封装了解决问题的步骤, 面向对象是更高级的语言, 但它是依赖于面向过程而存在的, 随着计算机科学与技术的发展, 出现更高级的语言也说不定呢?

本系列文章会持续更新! 大家踊跃的留下自己的脚印吧!

:footprints::footprints::footprints::footprints::footprints::footprints::footprints::footprints:


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Two Scoops of Django

Two Scoops of Django

Daniel Greenfeld、Audrey M. Roy / CreateSpace Independent Publishing Platform / 2013-4-16 / USD 29.95

Two Scoops of Django: Best Practices For Django 1.5 is chock-full of material that will help you with your Django projects. We'll introduce you to various tips, tricks, patterns, code snippets, and......一起来看看 《Two Scoops of Django》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

URL 编码/解码
URL 编码/解码

URL 编码/解码

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器