4.成员变量和访问修饰符

4.面向对象-封装-成员变量和访问修饰符


4.1 知识点

知识回顾:类和对象

  • 在 .h 结尾的头文件中声明类
  • 在 .cpp 结尾的源文件中定义类
  • 对于小型类或模板类,可直接在头文件中同时完成声明和定义

类的基本结构:

class 类名
{
    // 访问修饰符(可省略)
    // 构造函数、析构函数
    // 特征 —— 成员变量
    // 行为 —— 成员方法
    // ……
};

对象(实例化)的声明:

  1. 引用头文件

    #include "XXX.h"
    
  2. 普通对象(栈上)

    类名 变量名;
    类名 变量名 = 构造函数名(...);
    
  3. 指针对象(堆上)

    类名* 变量名 = new 构造函数名(...);
    
  4. 引用对象

    类名& 变量名 = 想要引用的对象;
    

成员变量

  • 声明在类的语句块中,用于描述对象的特征
  • 可以是任何变量类型,数量不做限制
  • 是否在声明时赋值可根据需求决定(老版本 C++ 只能在构造函数中初始化)
  • 不能有非指针类型的本类成员,否则会导致构造递归

示例:

#pragma once

enum E_SexType
{
    Man,
    Woman,
};
#pragma once
struct Position
{
    int x;
    int y;
    Position(int x, int y) : x(x), y(y) {}
};
#pragma once
class Pet {};
#pragma once
#include <iostream>
#include "Pet.h"
#include "Position.h"
#include "E_SexType.h"
using namespace std;
//类和枚举以及结构体 都可以独立的在.h头文件中进行声明和定义 要使用的时候 引用头文件即可
class Person
{
    //成员变量
    //1.用来描述 人 这种对象的特征
    //2.写在类语句块中
    //3.可以是任意的变量类型
    //4.数量不限制
    //5.是否赋值根据需求定 如果有构造函数可以在其中初始化 如果没有建议 都赋值一个初始值

    string name = "韬老狮";
    int age = 18;
    E_SexType sex = Man;
    Position pos = Position(4,5);


    //6.不能有非指针类型的自己类型的成员 否则 会出现构造函数递归
    //Person gridFriend;
    //Person friends[10];//数组也不行
    Person* gridFriend = nullptr;
    Person* friends[10] = { nullptr };

    //如果不是自己类型的类 是可以声明非指针的
    Pet pet = Pet();
    Pet* pet2 = nullptr;
};

默认是私有的无法直接使用:

//没声明访问修饰符前类不能直接使用 会提示不可访问编译报错 结构体才可以
//Person person;
//person.name = "tao";

访问修饰符(3P)

  • public:公共,内部和外部均可访问
  • private:私有,仅类内部可访问(默认)
  • protected:保护,对内部和子类开放,外部不可访问

示例:

#pragma once
#include <iostream>
#include "Pet.h"
#include "Position.h"
#include "E_SexType.h"
using namespace std;
//类和枚举以及结构体 都可以独立的在.h头文件中进行声明和定义 要使用的时候 引用头文件即可
class Person
{
    //成员变量
    //1.用来描述 人 这种对象的特征
    //2.写在类语句块中
    //3.可以是任意的变量类型
    //4.数量不限制
    //5.是否赋值根据需求定 如果有构造函数可以在其中初始化 如果没有建议 都赋值一个初始值
public:
    string name = "韬老狮";
    int age = 18;
    E_SexType sex = Man;
    Position pos = Position(4,5);

private:
    //6.不能有非指针类型的自己类型的成员 否则 会出现构造函数递归
    //Person gridFriend;
    //Person friends[10];//数组也不行
    Person* gridFriend = nullptr;
    Person* friends[10] = { nullptr };

    //如果不是自己类型的类 是可以声明非指针的
    Pet pet = Pet();
    Pet* pet2 = nullptr;
};

使用示例:

Person person;
person.name = "tao";
cout << person.name << endl;  // 输出:tao

成员变量的使用和初始化

  • 栈上创建

      Person p;
      p.age = 10;
      cout << p.age << endl;//10
      cout << p.name << endl;//韬老狮
      cout << p.pos.x << endl;//4
      cout << p.sex << endl;//0
    
  • 堆上创建

    Person* p2 = new Person();
    cout << p2->age << endl;  // 18
    
  • 必须对成员变量进行初始化:

    1. 在声明时直接赋初值
    2. 在构造函数中初始化
  • 如果我们不对成员变量进行初始化,那么他们的初始值会是一种不确定的状态。需避免此类情况。


总结

  • 成员变量用于描述对象特征,声明在类内部,类型和数量不受限
  • 必须初始化,且不能有非指针的本类类型成员
  • 访问权限由 publicprivateprotected 决定
  • 结构体、枚举和类的使用方式类似,均可在 .h 文件中声明与定义,使用时包含头文件即可

4.2 知识点代码

E_SexType.h

#pragma once

enum E_SexType
{
    Man,
    Woman,
};

Position.h

#pragma once
struct Position
{
    int x;
    int y;
    Position(int x, int y) : x(x), y(y) {}
};

Pet.h

#pragma once
class Pet {};

Person.h

#pragma once
#include <iostream>
#include "Pet.h"
#include "Position.h"
#include "E_SexType.h"
using namespace std;
//类和枚举以及结构体 都可以独立的在.h头文件中进行声明和定义 要使用的时候 引用头文件即可
class Person
{
    //成员变量
    //1.用来描述 人 这种对象的特征
    //2.写在类语句块中
    //3.可以是任意的变量类型
    //4.数量不限制
    //5.是否赋值根据需求定 如果有构造函数可以在其中初始化 如果没有建议 都赋值一个初始值
public:
    string name = "韬老狮";
    int age = 18;
    E_SexType sex = Man;
    Position pos = Position(4,5);

private:
    //6.不能有非指针类型的自己类型的成员 否则 会出现构造函数递归
    //Person gridFriend;
    //Person friends[10];//数组也不行
    Person* gridFriend = nullptr;
    Person* friends[10] = { nullptr };

    //如果不是自己类型的类 是可以声明非指针的
    Pet pet = Pet();
    Pet* pet2 = nullptr;
};

Lesson04_面向对象_封装_成员变量和访问修饰符.cpp

#include <iostream>
#include "Person.h"
int main()
{
    #pragma region 知识回顾 类和对象
    // 声明类
    // 类一般
    // 在.h结尾的头文件中声明
    // 在.cpp结尾的源文件中定义
    // 对于小型类或者模板类,可以在头文件中直接完成声明和定义

    //class 类名
    //{
        //访问修饰符:(可省略)
        //构造函数、析构函数
        //特征——成员变量
        //行为——成员方法
        //等等
    //};

    //声明 类对象
    //步骤一:引用类头文件

    //步骤二:声明对象
    //普通对象(栈上)
    //类名 变量名;
    //类名 变量名 = 构造函数名(...);

    //指针对象(堆上)
    //类名* 变量名 = new 构造函数名(...);

    //引用对象(根据引用对象自己决定在栈还是堆)
    //类名& 变量名 = 想要引用的对象;
    #pragma endregion

    #pragma region 知识点一 成员变量
    //基本规则
    //1.声明在类语句块中
    //2.用来描述对象的特征
    //3.可以是任意变量类型
    //4.数量不做限制
    //5.是否赋值根据需求来定(老版本C++中不能直接在声明时赋值,只能在构造函数中赋值)
    //6.不能有非指针类型的自己类型的成员



    //没声明访问修饰符前类不能直接使用 会提示不可访问编译报错 结构体才可以
    //Person person;
    //person.name = "tao";

    #pragma endregion

    #pragma region 知识点二 访问修饰符
    // 3P
    // public —— 公共的  自己(内部)和别人(外部)都能访问和使用(完全公开,任何地方都能访问)
    // private —— 私有的  自己(内部)才能访问和使用  不写 默认为private(严格私有,只有当前类内部才能访问)
    // protected —— 保护的  自己(内部)和子类才能访问和使用(对自己和子类开放,外部不可访问)
    // 决定类内部的成员 的 访问权限

    //声明访问修饰符后类可以直接使用 
    Person person;
    person.name = "tao";
    cout << person.name << endl;//tao

    #pragma endregion

    #pragma region 知识点三 成员变量的使用和初始值

    //栈上
    Person p;
    p.age = 10;
    cout << p.age << endl;//10
    cout << p.name << endl;//韬老狮
    cout << p.pos.x << endl;//4
    cout << p.sex << endl;//0

    //堆
    Person* p2 = new Person();
    cout << p2->age << endl;//18

    //一定要对类中的成员变量进行初始化
    //1.在声明时 直接初始化
    //2.在构造函数中初始化

    //如果我们不对成员变量进行初始化
    //那么他们的初始值会是一种不确定的状态
    //我们一定要避免这种情况
    //因此我们需要对他们进行初始化

    #pragma endregion


    //总结
    //成员变量
    //描述特征
    //类中声明
    //数量任意
    //类型任意
    //一定要初始化
    //不能有非指针类型的自己类型的成员
    // 
    //3p
    //public 公共 内外
    //private 私有 内
    //protected 保护的 内和子类

    //结构体、枚举可以在.h头文件中声明和定义
    //要使用时和类一样 引用头文件即可
}

4.3 练习题

3P是什么?

public:公共的 内外
private:私有的 内
protected:保护的 内和子类

定义一个人类,有姓名,身高,年龄,家庭住址等特征 用人创建若干个对象

#pragma once
#include <iostream>
using namespace std;

class Person
{
public:
    string name = "";
    float height = 0;
    int age = 0;
    string homeAddress = "";
};
Person p;
p.name = "韬老狮";
p.age = 18;
p.height = 190;
p.homeAddress = "广州";

Person* p2 = new Person();
p2->name = "主席";
p2->height = 180;
p2->age = 16;
p2->homeAddress = "北京";
delete(p2);
p2 = nullptr;

定义一个学生类,有姓名,学号,年龄,同桌等特征。用学生类创建若干个学生

#pragma once
#include <iostream>
using namespace std;

class Student
{
public:
    string name = "";
    int num = 0;
    int age = 0;
    Student* deskmate = nullptr;
};
Student s;
s.name = "小明";
s.age = 6;
s.num = 1;

Student s2;
s2.name = "小红";
s2.age = 6;
s2.num = 1;

s.deskmate = &s2;
s2.deskmate = &s;

定义一个班级类,有专业名称,教室容量,学生等 创建一个班级对象

#pragma once
#include <iostream>
#include "Student.h"
using namespace std;

class Class
{
public:
    string name = "";
    int capacity = 30;
    Student* students[30] = {nullptr};
};
Class* c = new Class();
c->name = "游戏开发";
c->capacity = 30;
c->students[0] = &s;
cout << c->students[0]->name << endl;
c->students[1] = &s2;
cout << c->students[1]->name << endl;

值类型赋值测试一

Person p;
p.age = 10;
Person p2;
p2.age = 20;

请问 p.age 为多少?

cout << person.age << endl; //10 互相独立没有任何关系

值类型赋值测试二

Person p;
p.age = 10;
Person p2 = p;
p2.age = 20;

请问 p.age 为多少?

//请问person.age为多少?
cout << person.age << endl; //10 不是new 在栈上是复制一份 改person2不会影响person

栈上值类型赋值测试

Student s;
s.age = 10;
int age = s.age;
age = 20;

请问 s.age 为多少?

cout << student.age << endl; //10 在栈上是复制一份

指针引用赋值测试

Student s;
s.deskmate = new Student();
s.deskmate.age = 10;
Student* s2 = s.deskmate;
s2.age = 20;

请问 s.deskmate.age 为多少?

cout << student.deskmate->age << endl; //20
//deskmate 是存的在堆上开辟的Student对象的地址
//student2赋值deskmate 存的也是地址 
//指向的是同一个内存区域 修改对应内存上的值都会受到影响

4.4 练习题代码

StuClassdent.h

#pragma once
#include <iostream>
#include "Student.h"
using namespace std;
class Class
{
public:
    string name = "";
    int capacity = 30;
    Student* students[30] = {nullptr};
};

Person.h

#pragma once
#include <iostream>
using namespace std;
class Person
{
public:
    string name = "";
    float height = 0;
    int age = 0;
    string homeAddress = "";
};

Student.h

#pragma once
#include <iostream>
using namespace std;
class Student
{
public:
    string name = "";
    int num = 0;
    int age = 0;
    Student* deskmate = nullptr;
};

Lesson04_练习题.cpp

#include <iostream>
#include "Person.h"
#include "Student.h"
#include "Class.h"
int main()
{
    #pragma region 练习题一
    //3P是什么?
    //public:公共的 内外
    //private:私有的 内
    //protected:保护的 内和子类
    #pragma endregion

    #pragma region 练习题二

    /*定义一个人类,有姓名,身高,年龄,家庭住址等特征
    用人创建若干个对象*/

    Person p;
    p.name = "韬老狮";
    p.age = 18;
    p.height = 190;
    p.homeAddress = "广州";

    Person* p2 = new Person();
    p2->name = "主席";
    p2->height = 180;
    p2->age = 16;
    p2->homeAddress = "北京";
    delete(p2);
    p2 = nullptr;

    #pragma endregion

    #pragma region 练习题三

    //定义一个学生类,有姓名,学号,年龄,同桌等特征。用学生类创建若干个学生

    Student s;
    s.name = "小明";
    s.age = 6;
    s.num = 1;

    Student s2;
    s2.name = "小红";
    s2.age = 6;
    s2.num = 1;


    s.deskmate = &s2;
    s2.deskmate = &s;

    #pragma endregion

    #pragma region 练习题四

    //定义一个班级类,有专业名称,教室容量,学生等
    //创建一个班级对象

    Class* c = new Class();
    c->name = "游戏开发";
    c->capacity = 30;
    c->students[0] = &s;
    cout << c->students[0]->name << endl;
    c->students[1] = &s2;
    cout << c->students[1]->name << endl;

    #pragma endregion

    #pragma region 练习题五

    //Person person;
    //person.age = 10;

    //Person person2;
    //person2.age = 20;
    ////请问person.age为多少?

    //cout << person.age << endl;//10 互相独立没有任何关系

    #pragma endregion

    #pragma region 练习题六

    Person person;
    person.age = 10;
    Person person2 = person;
    person2.age = 20;

    //请问person.age为多少?
    cout << person.age << endl;//10 不是new 在栈上是复制一份 改person2不会影响person

    #pragma endregion

    #pragma region 练习题七

    //Student student;
    //student.age = 10;
    //int age = student.age;
    //age = 20;
    ////请问student.age为多少?
    //cout << student.age << endl;//10 在栈上是复制一份 

    #pragma endregion

    #pragma region 练习题八

    Student student;
    student.deskmate = new Student();
    student.deskmate->age = 10;
    Student* student2 = student.deskmate;
    student2->age = 20;
    //请问student.deskmate->age为多少?

    cout << student.deskmate->age << endl;//20
    //deskmate 是存的在堆上开辟的Student对象的地址
    //student2赋值deskmate 存的也是地址 
    //指向的是同一个内存区域 修改对应内存上的值都会受到影响 

    #pragma endregion

}


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏