当前位置: 代码迷 >> 综合 >> 《C/C++学习指南》语法篇—笔记 (十七、面向对象编程 类)
  详细解决方案

《C/C++学习指南》语法篇—笔记 (十七、面向对象编程 类)

热度:40   发布时间:2024-02-08 04:02:04.0

《C/C++学习指南》语法篇—笔记 (十七、面向对象编程 类)

        • 类(class)
        • 类的成员
        • This指针
        • 重命名问题与名命规范
        • 类的封装
        • class的分离式写法
        • 类的构造函数
        • 类的析构函数
        • 默认构造函数
        • 成员的初始化与析构

面向对象编程,一种设计思想
面向对象编程的实现:

  • 假设存在一个对象,初步设想它应该提供哪些服务。
  • 定义如何使用它的服务,细化为函数。创建销毁对象,其它功能函数(该对象提供的服务)
  • 选择一种实现方法,写程序完成上述函数接口。

类(class)

是对结构体struct的增强,也是用于自定义类型。将关键字struct改为class;增加访问修饰符 pubilc/private/protected

class Object
{
public:int a;   //a,b成员变量double b;
};

访问成员变量的方法,与struct完全相同

Object Obj;
obj.a = 11;
obj.b = 12.0;Object* p = &Obj;
p->a = 12;
p->b = 13.0;

访问修饰符:public,private,propected用于表示类的成员函数是否允许被外部访问。

  • pubilc :公开的,所列的成员可被外部访问
  • private :私有的,所列的成员不可以被外部访问
  • protected :受保护的,不可以被外部访问,可以被继承

访问修饰符后面加:,一般顶格书写,不缩进,每个一行,每个成员变量只受前一个修饰符的限制。如果没有访问修饰符,默认是private的。

类的成员

成员变量成员函数。在类体中,成员函数和变量的排列顺序的自由的。
定义在class内的函数,称为该类的成员函数。成员函数的访问,也是用.->,成员函数同成员变量一样受访问修饰符的限制。

class Object
{
public:int a;void Test(){printf("hello! \n");}
};Object Obj;
obj.Test();
Object* p = &Obj;
p->Test();

This指针

在类里打印出a:

class Object
{
public:int a;void Test(Object* that){//打印aprintf("a=%d \n",that->a);}
};
Object Obj;
Obj.Test(&Obj);

使用this指针方法简化:当Test被调用时,已经把对象Obj的指针传给它了。使用this指针,可以直接访问本类的其他成员(变量,函数),不受public/private的限制。this就是本对象的地址,在形式上做了一个简化,使得用户少传一个对象指针作为参数。
在类的函数里面,this可以省略,编译器会自己添加this->

class Object
{
public:int a;
private:int b;  //b是private的,但this->可以访问
public:void Test(){//打印aprintf("a=%d,b=%d \n",this->a,this->b);printf("a=%d,b=%d \n",a,b);  //省略this->}
};
Object Obj;
Obj.Test();

重命名问题与名命规范

就近原则:

  • 在成员函数里,当局部变量与成员变量重名时,该变量指的是局部变量。如果要指定成员变量,则必须加上this->
  • 在成员函数里,当成员变量与全局变量重名时,该变量指向的是成员变量。如果要指定全局变量,则必须加上 ::
  • 在成员函数与全局函数重名时,默认指成员函数。
  • ::全局符号 this->成员

名命规范:

  • 类名:每个单词的首字母大写,一般用名词形式
  • 成员函数:每个单词首字母大写,一般用动词形式
  • 成员变量:小写开头,第二个单词开头大写,通常加上前缀m_number

类的封装

封装:把细节隐藏在内部,只把函数接口暴露在外。在C/struct中,由于struct内部是可以自由访问,所以无法实现封装(用户可能不小心破坏内部数据),在引入class和访问修饰符后,就可以实现完全的封装。

  • 把所有成员变量设为private
  • 添加函数接口,供外部操作该对象,及其他功能接口

成员变量:

  • 完全公开:用public修饰符
  • 完全不允许访问:用private
  • 只读:getter,写个pubilc访问该成员变量的函数
  • 只写:setter,写个public设置该成员变量的函数

class的分离式写法

把class的成员函数定义在class之外,即class的大括号外面。

  • 成员变量:写在类里面
  • 成员函数:在类里保留其函数声明,而函数的定义写在类体之外
  • 函数定义写在外面的时候,要加上类名限定(Object::),::理解为表示范围的符号。

分开为头文件 Object.h

class Object
{
public:int x;void Test();
};

源文件 Object.cpp

#include <stdio.h>
#include "Object.h"void Object::Test()
{printf("x is %d \n",x);  //仍然可省略this->
}

类的构造函数

一种特殊的成员函数

  • 函数名与类名必须相同
  • 没有返回值
  • 构造函数可以带参数,也可以重载!!!
class Cricle
{
...
public:Cricle(){x=y=0;radius = 1;}Cricle(int x, int y, int r){this->x = x;  //这里要加this了吧~this->y = y;this->radius = r;}
};

构造函数如何调用:
构造函数和普通函数不一样,一般不显式调用,在创建一个对象时,构造函数被自动调用,由编译器完成

Cricle a;  //调用第一个不带参数的构造函数
Cricle a(1,1,4);   //调用后一个

构造函数作用:对象的初始化动作
例如下面基本类型的初始化:

int a(10);  // 和 int a = 10; 一样
Struct s= {1,"aa"};  //某个结构体的初始化

类的析构函数

  • 名称固定:类名前加~
  • 没有返回值
  • 不能带参数,只有一个,不允许重载
class Object
{
...
public:~Object(){}
}

调用:
构造函数:对象被创建时被调用
析构函数:对象被销毁时被调用(不显式调用,被编译器自动调用),对于局部变量(对象),在超出变量作用域(某大括号)后,该对象失效,自动调用析构。
作用:
对象在销毁之前,做一个清理善后工作,例如释放申请的内存,关闭打开的文件。

.h/.cpp分离写法

class DataStore
{
public:DataStore();  //函数声明~DataStore();
};DataStore::DataStore(){}
DataStore::~DataStore(){}

默认构造函数

不需要传参的构造函数,或所有参数都有默认缺省值,称为默认构造函数。

Object();
Object(int a=10, int b=11);

默认构造函数是重要的,在构造数组对象的时候,没有默认构造函数则无法构造。
如果一个类没有写任何构造函数,则编译器隐含的为其添加一个构造/析构函数。只有当没写的时候才给添加,一旦写了一个,就不给添加了。

Object objs[4];

成员的初始化与析构

成员变量本身也是class类型时:

  • 构造:成员被依次构造:从前到后;先执行成员的构造函数,再执行自己的构造函数
  • 析构:成员为依次析构:从后到前;先执行自己的析构函数,再执行成员的析构。

初始化列表!!!
1、基本类型的初始化:

class Object{
public:Object():x(1),y(2){}
};

2、class类型的初始化:

//初始化(和赋值功能上一样,性能上有时节省CPU操作)

class Object{
public:Object():m_chlid(1,2){}
};

//赋值

class Object{
public:Object()  //已经对m_child进行了构造{m_child.x = 1;m_child.y = 2; //又多了一步操作}
};