Class in C++

Posted by JHSN on December 12, 2016

1. 类的框架


类是 C++ 相较于 C 的核心feature,用于面向对象程序设计(OOP),封装各种自定义类型。
类由数据和函数两种成员构成,每个成员带有由访问修饰符(private protected public)控制的访问属性,对象用 “.” 或 “->” 访问成员。(详见下节的 example)

class <className>       //定义类
{
    private:
        // ...
    protected:
        // ...
    public:
        // ...
};
<className> <objName>;  //定义对象

谁能访问三种类访问修饰符下的内容?

private:    该类的函数 友元函数(friend声明)
protected:  该类的函数 友元函数 子类函数
public:     该类的函数 友元函数 子类函数 该类对象
* 注意:C++ 中 struct 默认 public 属性,class 默认 private(继承也是一样)


2. 类的函数


类可定义几种函数:

  1. 构造函数 / 拷贝构造函数
  2. 析构函数
  3. 友元函数
  4. 普通的方法

For example:

#include<cstdio>
#include<cstdlib>

class Person    //代码规范建议 类首字母大写
{
    private:
        int vessulLen = INT_MAX;
    
    public:
        int legNum, emotion;
        double weight;
        
        Person(const double w)      //构造函数 创建对象时执行
        {
            puts("A person was born!");
            emotion = 100;
            legNum = 2;
            weight = w;
        }
        
        Person(const Person &obj)   //拷贝构造函数 创建对象时执行
        {
            puts("A person was born!");
            emotion = obj.emotion;
            legNum = obj.legNum;
            weight = obj.weight;
        }
        
        ~Person(void)               //析构函数 释放对象时执行
        {
            puts("A person died!");
        }
        
        void eat(int, double);
};

void Person::eat(int foodValue, double foodWeight)
{
    emotion += foodValue;
    weight += foodWeight;
}    //利用 :: 可以在类外部定义函数,但需要在类中事先声明

int main()
{
    Person jhon(50);    //创建一个名为 jhon 的对象
    jhon.eat(20, 1);    //直接调用 eat
    Person mike(jhon);  //拷贝 jhon
    printf("John: %d %.3lf\n", jhon.emotion, jhon.weight);
    mike.eat(10, 0.1);
    printf("Mike: %d %.3lf\n", mike.emotion, mike.weight);
    return 0;
}

Output:

A person was born!
A person was born!
John: 120 51.000
Mike: 130 51.100
A person died!
A person died!



3. 类的指针


包括但可能不限于:

  1. this 指针:类的所有成员函数的隐含参数
  2. 指向类的指针
  3. 指向成员函数的指针
  4. 以指针形式定义的对象

For example:

bool Person::bigger(Person *obj)
{
    return this->weight > obj->weight;
}

int main()
{
    Person jhon(50);        //直接定义的对象
    Person *p = &jhon;      //指向 jhon 的指针
    Person* mike = new Person(jhon);    // mike 为以指针形式定义的对象
    mike->eat(10, 10);      //调用 eat
    double *q;
    q = &mike->weight;      //指向 mike 的体重 
    printf("- Is Mike bigger than jhon?\n- ");
    puts( mike->bigger(p) ? "Yes." : "No.");
    delete mike;
    p = NULL;
    return 0;
}

Output:

A person was born!
A person was born!
- Is Mike bigger than jhon?
- Yes.
A person died!
A person died!


4. 类的继承


继承

被继承的类称为基类/父类,继承的类称为派生类/子类
子类继承了基类所有的成员,但
不继承:

  1. 构造函数 / 拷贝构造函数
  2. 析构函数
  3. 友元函数
  4. 重载运算符

不可访问:基类 private 下的内容

继承方式:

//单基类继承
class <derivedClass> : <accessSpecifier> <baseClass>
{
    // ...
};

//多基类继承
class <derivedClass> : <accessSpecifier1> <baseClass1>, 
                       <accessSpecifier2> <baseClass2>, 
                       ...
{
    // ...
};

其中accessSpecifier 分为

1. public    公有继承(usually):基类的公有/保护成员 -> 子类的公有/保护成员
2. protected 保护继承         :基类的公有/保护成员 -> 子类的保护成员
3. private   私有继承(default):基类的公有/保护成员 -> 子类的私有成员

多态

继承关系中的父子类可以声明同名同参数函数,而多态指调用继承关系中的类的成员函数时,根据类的不同执行不同方法的相同接口函数,即“一个接口,多种方法”。
默认未定义的情况下,父子类均会绑定父类的成员函数,此称为静态绑定/早期绑定
若要实现动态绑定/后期绑定,则需要使用关键字 virtual 在父类中声明虚函数
* 注意:静态函数不能被声明为 virtual

virtual <functionType> <functionName>
{
    // ...
}

virtual <functionType> <functionName> = 0;  //无操作的纯虚函数

See also几个复杂的坑: 重载、重写(覆盖)、隐藏(重定义)、多态性


5. 类中的重载


重载函数

重载函数间基本性质:

  1. 函数名必须相同
  2. 参数类型个数必须不同
  3. 必须处于同一作用域下
  4. 与访问权限、返回类型、抛出的异常无关

For example:

class Example
{
    public:
        int add(int a, int b) {
            return a + b;
        }
        void add(int &a) {
            a++;
        }
        double add(double a, double b) {
            return a + b;
        }
};

重载运算符

class <className>
{
    public:
        <retType> operater<operater>(<arguments>)
        {
            // ...
            return ...;
        }
};



评论区加载中