C++学习笔记2:面向对象基础(一)

面向对象基础(一)

  • 面向对象概念
    • 面向对象编程(OOP)
      • 特征(A Pie)
    • 对象(Object)的构成
    • 定义对象(Object)
      • 类(Class)
  • 用类创建对象
    • 声明类
      • 构造函数
    • 创建对象
      • 不带参数
      • 带参数
    • 访问对象
    • 将类的声明与实现分离
      • 实例
      • 内联声明与内联函数
      • 避免头文件多次包含
  • 对象拷贝与匿名对象
    • 定义对象的多种方式
    • 成员拷贝
    • 匿名对象
    • 结构体的弃用
    • 局部类与嵌套类

面向对象概念

面向对象编程(OOP)

OOP: Object-Oriented Programing (OOP). 面向对象编程

对象:一个对象表示现实世界中一个独一无二的实体

举例:一个学生,一张桌子,一个圆圈,一个按钮,甚至一笔贷款都可以看成是对象

特征(A Pie)

  1. Abstraction (抽象)
  2. Polymorphism (多态)
  3. Inheritance (继承)
  4. Encapsulation (封装)

我们将这四个单词的首字母放在一起: A PIE

中文含义是:一块甜饼。 这样记忆就方便多了。

对象(Object)的构成

  • 对象具有唯一的标识、状态和行为
  • 对象状态由数据域(也称为“属性”)及其当前值构成
  • 对象的行为由一组函数(方法)定义

定义对象(Object)

对象是类的实例

可以看成,类是一种由程序员定义的数据类型。

简单的对比,以前数据类型是int/double,现在变成了类ClassName;以前变量可以用int/double定义,如int a,现在<对象>由类进行实例化,如ClassName ObjectName

类(Class)

类包含:

  • Data Fields,由变量定义的数据域,有时又称为<属性>
  • Behaviors,由函数定义的行为,有时又称为<方法>

类有两种特殊的函数:

  • Constructors(ctor):构造函数:在创建对象时被自动调用
  • Destructors(dtor):析构函数:在对象被销毁时被自动调用

用类创建对象

声明类

实例:

class Circle {
private:
    double radius;
public:
    // 无参构造函数(默认构造函数)
    // [C++11]:default,在有含参构造函数的情况下,同时让编译器生成一个重载的无参(默认)构造函数
    Circle() = default;

    // 含参构造函数
    Circle(double r) {
        radius = r;
    }

    // 设置半径
    void setRadius(double r) {
        radius = r;
    }

    // 获取半径
    double getRadius() const {
        return radius;
    }

    // 获取面积
    double getArea() const {
        return 3.14 * radius * radius;
    }
};

构造函数

特点:

  1. 自动调用
  2. 与类同名
  3. 无返回值
  4. 可重载
  5. 可不带参数

类可不声明构造函数:

  1. 编译器会提供一个带有空函数体的无参构造函数

  2. :只有当未明确声明构造函数时,编译器才会提供这个构造函数,并称之为“默认构造函数”

    比如,上述代码段中,我们明确了一个含参构造函数Circle(double r);,那么编译器不会自动生成无参(默认)构造函数,需要程序员自己声明。

    即:上述代码,去掉语句Circle() = default;后,无法通过编译。同时,default关键字是C++11开始有的,该语句等同于Circle() {}

    如果将上述代码的两个构造函数都删去,可通过编译,表明了<类可不声明构造函数>

创建对象

不带参数

创建一个对象,不传递参数。

Circle circle1;		// 正确,但不推荐这样写
Circle circle2();	// 错误!C++编译器认为这是一个函数声明
Circle circle3{};	// 正确,推荐写法。这里面明确显示用空初始化列表初始化circle3对象(调用Circle默认构造函数)

带参数

创建一个对象,创建的同时传递参数,用于初始化该对象。

Circle circle2{ 5.5 }; // C++11 列表初始化
// 带有窄化检查(narrowing check)

访问对象

使用点运算符<.>访问对象中的数据函数。

点运算符<.>,也称为对象成员访问运算符。

要注意的是,点运算符<.>只能访问类的公有(public)成员,将在《封装》一节详解。

将类的声明与实现分离

C++中,类声明与实现可以分离:

  1. .h: 类声明,描述类的结构
  2. .cpp: 类实现,描述类方法的实现

类的声明语法如下:

// In .h File
class ClassName {
private:
    DataType1 DataName1;
    DataType2 DataName2;
public:
    FunctionType1 FunctionName1(Arguments);
    FunctionType2 FunctionName2(Arguments);
}

类的实现语法如下:

// In .cpp File
FunctionType ClassName::FunctionName (Arguments) {
    // Function body
}

其中,:: 这个运算符被称为binary scope resolution operator(二元作用域解析运算符),简称“域分隔符”。

实例

Circle.h文件:

#ifndef CIRCLE_H_
#define CIRCLE_H_

class Circle {
private:
    double radius;
public:
    // 无参构造函数(默认构造函数)
    Circle();
    // 含参构造函数
    Circle(double r);
    // 设置半径
    void setRadius(double r);
    // 获取半径
    double getRadius() const;
    // 获取面积
    double getArea() const;
};

#endif /* CIRCLE_H_ */

Circle.cpp文件:

Circle::Circle() = default;

Circle::Circle(double r) {}

void Circle::setRadius(double r) {
    radius = r;
}

double Circle::getRadius() const {
    return radius;
}

double Circle::getArea() const {
    return 3.14 * radius * radius;
}

main.cpp文件(实例演示,创建一个Circle对象):

#include 
#include "Circle.h"
using std::cout;
using std::endl;

int main() {
    Circle c;
    c.setRadius(1);
    cout << c.getArea() << endl;
    return 0;
}

编译这个C++程序的命令是:g++ main.cpp Circle.cpp -o main,或者使用集成开发环境。

内联声明与内联函数

当函数在类声明中实现,它自动成为内联函数。

也就是,如果函数体直接写在类的声明种,该函数自动成为内联函数。

实例:

class A {
public:
  A() = default; //C++11
  double f1() {  // f1自动称为内联函数
    // do something
  } 
  double f2();
};

double A::f2() {  // f2不是内联函数
  //do something
}
class A {
public:
  A() = default; //C++11
  double f1();
  double f2();
};

double A::f2() {
  //do something
}

inline double A::f1() { // f1是内联函数
  //do something
}

避免头文件多次包含

.h文件中可以使用三种编译预处理指令:

#ifndef MY_HEADER_FILE_H
#define MY_HEADER_FILE_H
//  头文件内容
#endif
#pragma once // C++03, C90
_Pragma("once") // C++11, C99;
// 如果是MSVC编译器,那么是:
__pragma(once);

对象拷贝与匿名对象

定义对象的多种方式

用类声明一个实体的说法,与定义变量的说法有些不同:用原生数据类型定义变量,用类名定义对象

// class --> objects

Circle c1;      //调用Circle的默认ctor

Circle c2(5.5); //调用Circle的有参ctor,不推荐这种语法

Circle c3{5.5}; // 直接列表初始化,调有参ctor

Circle c4 = {5.5}; // 拷贝列表初始化,调ctor

auto c5 = Circle{2.}; // auto类型推断

decltype(c1) c6;      // decltype类型推断

成员拷贝

如何将一个对象的内容拷贝给另外一个对象?

  • 使用赋值运算符<=>

  • 默认情况下,对象中的每个数据域都被拷贝到另一对象的对应部分

实例:

Circle c1{2.0};
Circle c2;

c2 = c1
  • 将c1 的radius 拷贝到c2 中
  • 拷贝后:c1 和 c2 是两个不同的对象,但是半径的值是相同的。( 但是各自有一个radius 成员变量)

匿名对象

有时需要创建一个只用一次的对象,这种不命名的对象叫做匿名对象( Anonymous Object)。

实例:

int main() {
  Circle c1 = Circle{1.1};
  auto c2 = Circle{2.2}; // 用匿名对象做拷贝列表初始化
  Circle c3{};           // 直接列表初始化,调默认Ctor
  c3 = Circle{3.3};      // 用匿名对象赋值
  cout << "Area is " << Circle{4.2}.getArea() << endl;
  cout << "Area is " << Circle().getArea() << endl;  // 不推荐的语法
  cout << "Area is " << Circle(5).getArea() << endl; // 不推荐的语法
  return 0;
}

注意到,上述代码第2、3行,使用了匿名对象对c1、c2做初始化。而第5行,使用了匿名对象对c3进行了成员拷贝(也可以叫做对c3对象进行了赋值操作)。

结构体的弃用

C语言中使用结构体类型来表示一组数据。

在C++中,结构体已被取代。

局部类与嵌套类

  • 局部类是在一个函数中声明的类。

实例:

void f(){
  class C { // C及其对象只在f()中可用 
    void g() { // 成员函数必须在C中实现
      /* 访问f()的成员受限 ……. */
    }
  };
  C c1, c2;
}

嵌套类是在另一个类中声明的类。

实例:

class E{
  class N { // N及其对象可访问E的成员 
    /* 声明N的成员 ……. */
    }
  };
  N n1, n2;
}

你可能感兴趣的:(学习笔记,C/C++,c++)