C++-面向对象

218 阅读6分钟

类和对象

类的定义

类定义的通常结构为:

image-20221029183924272

class Box
{
private: // 访问修饰符
    // 定义数据类型
    double length;
    double breadth;
    double height;

public:
    // 定义类型成员
    typedef int a_type;
    // 成员函数声明
    double get(void);
    void set(double len, double bre, double hei);
};
// 成员函数定义
double Box::get(void)
{
    return length * breadth * height;
}

void Box::set(double len, double bre, double hei)
{
    length = len;
    breadth = bre;
    height = hei;
}

成员函数的两种定义方式

在类体内定义

在类体内定义的函数默认是内联函数.

内联函数:在编译时候,若普通函数A()调用了内联函数inline B(),则在编译时,在A()中,会使用B()的函数体来替换原本使用B()的地方.而普通函数则需要在运行A()时,才会使用函数调用机制进行调用.内联函数是一种空间换时间的方法,通过使用内联函数,减少了函数调用次数,但是却增加了编译后的体积(只要有调用内联函数B()的地方,就会进行展开).

内联函数和宏定义共同之处是都需要在使用时进行展开,而不是进行函数调用.区别在于: 1: 时间不同,宏定义在预处理时进行替换,内联函数在编译时进行替换 2: 功能不同:内联函数会检查参数类型,所以更安全

内联函数用的地方不多,它会将函数调用处用函数体替代,所以一般在类体内部对成员函数作声明,而在类体外部进行定义.

如果函数体较小,且用的比较多,那么定义内联函数也挺好.

在类体外通过::定义

::被称为域解析符(也称作用域运算符作用域限定符),用来连接类名和函数名,指明当前函数属于哪个类。(命名空间也是用这个解析符)

class Student{
public:
    //成员变量
    char *name;
    int age;
    float score;
    //成员函数
    void say();  //函数声明
};
//在类体外进行函数定义
void Student::say(){
    cout<<name<<"的年龄是"<<age<<",成绩是"<<score<<endl;
}

构造函数与析构函数

类的构造函数可以使用两种方式进行定义:

  1. 常规写法
  2. 初始化列表

常规写法

#include <iostream>
using namespace std;
class Student{
private:
    char *m_name;
    int m_age;
    float m_score;
public:
    //声明构造函数
    Student(char *name, int age, float score);
    //声明普通成员函数
    void show();
};
//定义构造函数
Student::Student(char *name, int age, float score){
    m_name = name;
    m_age = age;
    m_score = score;
}

使用初始化列表方式定义构造函数


//采用初始化列表方式定义构造函数
Student::Student(char *name, int age, float score): m_name(name), m_age(age), m_score(score){
    //TODO:
}
//定义普通成员函数
void Student::show(){
    cout<<m_name<<"的年龄是"<<m_age<<",成绩是"<<m_score<<endl;
}

创建对象


int main(){
    //在栈上创建对象时向构造函数传参
    Student stu("小明", 15, 92.5f);
    stu.show();
    //在堆上创建对象时向构造函数传参
    Student *pstu = new Student("李华", 16, 96);
    pstu -> show();

    return 0;
}

两种定义方式的区别

  1. 两种方式效率相同,但是如果类有成员常量(const),就需要使用初始化列表方式
  2. 初始化常量方式以:为标志

成员函数的定义规则

常量成员函数

如果将const关键字放在函数的参数列表后面,表示该函数为常量成员函数.example:int max(a,b) const{}.常量成员函数的一个最重要的特点就是:无法通过常量成员函数来修改成员变量的值.如果要通过常量成员函数修改成员变量,则编译器会报错.

const对象只能调用常量成员函数.

建议:但凡是不能要求修改成员变量的函数,都设置成常量成员函数.

对象的定义

在不同的内存区域定义对象

定义对象的位置是否使用new返回类型特点
不用new对象本身在栈上创建一个对象,可以直接使用对象.
使用new对象的指针使用new关键字在堆上创建对象,使用后需要使用delete删除不再使用的对象,避免遗留大量垃圾

使用不同的方式进行对象创建

以此为例,介绍使用隐式调用,显式调用和new()来创建对象

class Student{
private:
    char *m_name;
    int m_age;
    float m_score;
public:
    //声明构造函数
    Student(char *name, int age, float score);
    //声明普通成员函数
    void show();
};
//采用初始化列表方式定义构造函数
Student::Student(char *name, int age, float score): m_name(name), m_age(age), m_score(score){
    //TODO:
}

创建对象方式

初始化方式使用自定义构造函数使用默认构造函数
显式调用构造函数Student stu = Student("张三",20,98.0);Student stu = Student();
隐式调用构造函数Student stu("张三",20,98.0);Student stu;
new创建Student *stu =new Student("张三",20,98.0);Student * stu = new Student;

explicit关键字

explicit是用来修饰类的构造函数的,被修饰的构造函数将不能通过隐式调用的方式创建对象,只能通过显式调用等方式创建.

其注意事项为:

  1. 只能用于类内部定义的构造函数(默认是内联的)
  2. 只能用于单参数的构造函数

继承

不同继承方式子类的权限

class 派生类名:[继承方式] 基类名{
    派生类新增加的成员
};

继承方式:public,protected,private.默认是private.

不同的继承方式会影响父类的成员在子类中的访问权限,不同继承方式指定子类继承父类的成员时对成员的最高访问权限

继承方式父类权限子类权限
publicpublicpublic
protectedprotected
private不能继承
protectedpublicprotected
protectedprotected
private不能继承
privatepublicprivate
protectedprivate
private不能继承

使用using关键字可以在子类中使用父类中的成员,改变父类中成员访问权限.

//基类People
class People {
public:
    void show();
protected:
    char *m_name;
    int m_age;
};
//派生类Student
class Student : public People {
public:
    void learning();
public:
    using People::m_name;  //将protected改为public
    using People::m_age;  //将protected改为public
    float m_score;
private:
    using People::show;  //将public改为private
};

接口(抽象类)

c++中,使用抽象类来实现接口. 抽象类:如果类中有至少一个遗憾被声明为纯虚函数,则该类就是抽象类.

纯虚函数:函数声明中,原型尾部有=0,如:

class Box{
public:// 纯虚函数
    virtual double getVolume() = 0;
private:
    double length;      // 长度      
    double breadth;     // 宽度      
    double height;      // 高度};

抽象类中,其声明的纯虚函数必须在子类中实现.

多继承

class D: public A, private B, protected C{
    //类D新增加的成员
}

子类成员函数规则

子类与父类函数不构成重载,只要函数名相同,无论参数列表如何,子类的函数就会覆盖父类定义的函数.

  • 类的构造函数不能被继承,但是可以调用父类的构造函数来简化对象构造过程.
  • 父类构造函数优先调用
  • 派生类构造函数中只能调用直接基类的构造函数,不能调用间接基类的
  • 调用析构函数时,优先调用子类的析构函数,其次才是父类的析构函数

总结

  • class内部成员默认是private,struct成员默认是public

REFERENCE

1. blog.csdn.net/u010248077/…