C++ day03(作用域限定符、this、static、const)

目录

【1】作用域限定符::

1》名字空间

2》类内声明,类外定义

【2】this关键字

1》概念

2》调用成员

3》区分重名的成员变量与局部变量

4》链式调用

【3】static关键字

1》静态局部变量

2》静态成员变量

3》静态成员函数

[【4】const 关键字](#【4】const 关键字)

1》修饰成员函数

[2》 修饰对象](#2》 修饰对象)

3》修饰成员变量


【1】作用域限定符::

1》名字空间

名字空间是一种代码的层级划分。

cpp 复制代码
#include <iostream>

using namespace std;
// C++课程中几乎所有的类型(不包括基本数据类型)都在std中

int a = 1;

// 新建一个名字空间
namespace my_space {
    int a = 3;
    string s = "哈哈哈";
}

namespace my_space2 {
    int a = 4;
    string s = "嘿嘿嘿";
}

// 使用自己的名字空间
using namespace my_space2;


int main()
{
    int a = 2;
    std::cout << "你好" << std::endl;//像cout cin endl这些都属于std名字空间的内容,使用了std名字空间之后就不再需要加std::了
    cout << a << endl; // 2
    cout << ::a << endl; // 1

    // 访问my_space的内容
    cout << my_space::a << my_space::s << endl;//加上名字空间说明调用的是哪一个名字空间的变量
    // 访问my_space2的内容
    cout << my_space2::a << s << endl;//使用my_space2名字空间后就不再需要加作用域限定符来区分了

    return 0;
}

2》类内声明,类外定义

函数是可以声明定义分离的,成员函数也可以声明定义分离,把成员函数的声明放置在类内,把成员函数的定义放在类外,因为定义在类外,所以需要加上**类名::**来指定定义的函数是哪一个类的。

cpp 复制代码
#include <iostream>

using namespace std;

class Student
{
private:
    string name;

public:
    // 类内声明
    Student(string n);
    string get_name();
    void set_name(string n);
};

// 类外定义
Student::Student(string n)//加上作用域限定符来指定是哪一个类的函数
{
    name = n;
}

string Student::get_name()
{
    return name;
}

void Student::set_name(string n)
{
    name = n;
}

int main()
{
    Student s("欢欢");
    s.set_name("刘欢");
    cout << s.get_name() << endl;

    return 0;
}

【2】this关键字

1》概念

this在类中表示一个指针:this指针,是一种特殊的指针,保存了当前类对象的首地址(指向当前类的对象)

cpp 复制代码
#include <iostream>

using namespace std;

class Student
{
private:
    string name;

public:
    Student(string n):name(n)
    {
        cout << this << endl;//输出当前对象的地址
    }

    string get_name()
    {
        cout << this << endl;//每次调用都看一下地址是多少
        return name;
    }

    void set_name(string n)
    {
        cout << this << endl;
        name = n;
    }
};



int main()
{
    //栈内存对象
    Student s("欢欢");
    cout << &s << endl;//直接取对象的地址
    s.set_name("刘欢");
    cout << s.get_name() << endl;

    cout << endl;

    //堆内存对象
    Student* s2 = new Student("hh");
    cout << s2 << endl;
    cout << s2->get_name() << endl;

    return 0;
}

2》调用成员

cpp 复制代码
#include <iostream>

using namespace std;

class Student
{
private:
    string name;

public:
    Student(string n)
    {
        this->name = n;//通过this调用的对象时当前类的对象
        cout << this->get_name() << endl;
    }

    string get_name()
    {
        return this->name;
    }

    void set_name(string n)
    {
        this->name = n;
    }
};

多数情况下在类内调用成员的时候(除去有可能出现重名的情况),如果程序员不写this指针,编译器都会在成员调用时自动添加this指针。

3》区分重名的成员变量与局部变量

cpp 复制代码
#include <iostream>

using namespace std;

class Student
{
private:
    string name;

public:
    Student(string name)//由于这时传过来的局部变量和成员变量重名,
//    所以这时就可以通过添加this指针来区分哪个是成员变量,哪个是局部变量
    {
        this->name = name;
    }

    string get_name()
    {
        return name;
    }

    void set_name(string name)
    {
        this->name = name;
    }
};



int main()
{
    Student s("Tom");
    cout << s.get_name() << endl;
    s.set_name("Jerry");
    cout << s.get_name() << endl;

    return 0;
}

4》链式调用

如果一个成员函数的返回值是当前类型的引用,说明这个函数支持链式调用,return的内容一定是*this。

cpp 复制代码
#include <iostream>

using namespace std;

class Value
{
private:
    int value;

public:
    Value(int value)
    {
        this->value = value;
    }

    Value& add(int value)//返回值是一个Value类的引用
    {
        this->value += value;
        return *this;//所以返回的时候是一个类对象
    }

    int get_value()
    {
        return value;
    }
};



int main()
{
    Value v1(0);
    // 普通的调用方式:分步操作
    v1.add(1);
    v1.add(2);
    v1.add(4);
    v1.add(7);
    cout << v1.get_value() << endl; // 14

    cout << endl;

    Value v2(0);
    // 链式调用
    //v2.add(1)执行完之后返回的仍然是一个对象,所以可以继续调用add函数,形成一个链式结构
    cout << v2.add(1).add(2).add(4).add(7).get_value() << endl; // 14
    cout << v2.get_value() << endl; // 14

    return 0;
}

【3】static关键字

1》静态局部变量

使用static修饰的局部变量就是静态局部变量 ,所在的函数第一次被调用时创建 ,直到程序运行结束才销毁 ,所有的对象共用这一个静态局部变量。

cpp 复制代码
#include <iostream>

using namespace std;

class Test
{
public:
    void test_static()
    {
        int a = 1;
        static int b = 1; // 局部静态变量,这个语句只有第一次执行到的时候会执行一次,之后就不会在执行了,
        //所以在后面值发生变化之后再运行到这也不会再初始化
        cout << a++ << endl;
        cout << b++ << endl << endl;
    }
};

int main()
{
    Test t1;
    Test t2;
    t1.test_static();//1 1
    t2.test_static();//1 2
    t1.test_static();//1 3

    return 0;
}

2》静态成员变量

使用 static 关键字修饰的成员变量就时静态成员变量。

静态成员变量有以下特点:

1.非 const 修饰的静态成员变量不能再类内初始化,必须在类外初始化。

2.同一个类的所有对象共享一份静态成员变量。

3.静态成员变量可以直接通过类名调用,无需关联任何对象,因为静态成员变量在程序执行时创建,在程序结束时销毁。

cpp 复制代码
#include <iostream>

using namespace std;

class Test
{
public:
    int a = 1; // 成员变量
    static int b; // 静态成员变量
};

int Test::b = 1; // 类外初始化

int main()
{
    // 通过类名直接调用静态成员变量
    cout << Test::b << " " << &Test::b << endl;

    Test t1;
    Test t2;
    cout << t1.a++ << " " << &t1.a << endl;
    cout << t2.a++ << " " << &t2.a << endl;//t1和t2的变量a是各自拥有的,所以地址不同
    cout << t1.b++ << " " << &t1.b << endl;
    cout << t2.b++ << " " << &t2.b << endl;//变量b是静态成员变量,共有的,所以t1和t2的b地址相同,和直接类名调用一样

    return 0;
}

3》静态成员函数

使用static 关键字修饰的成员函数就是静态成员函数。

静态成员函数有以下特点:

1.没有this 指针,因此不能调用非静态成员。

2.如果静态成员函数声明与定义分离,static 只需要写在声明处即可。

3.除了可以使用对象调用外,还可以直接通过类名::调用。

cpp 复制代码
#include <iostream>

using namespace std;

class Test
{
public:
    int a = 1;
    static int b;

    static void func(); // 静态成员函数,声明的时候写了 static关键字
};

int Test::b = 1;

void Test::func() // 类外定义,定义的时候就不再需要写 static 关键字
{
//        cout << a << endl; 错误,a不是静态成员变量,不能被静态成员变量调用
    cout << b << endl;
}

int main()
{
    Test t;
    t.func();//类对象调用

    Test::func();//类名直接调用

    return 0;
}

【4】const 关键字

1》修饰成员函数

const修饰的成员函数,表示常成员函数,可以调用非 const 的成员变量,但是不能修改数值,不能调用非 const 的成员函数。

如果成员函数的声明与定义分离,const在声明和定义处都要写。

cpp 复制代码
#include <iostream>

using namespace std;

class Test
{
private:
    string name;
public:
    void set_name(string name)
    {
        this->name = name;
    }

    string get_name() const; // 常成员函数

    void test_const() const // 常成员函数
    {
//        set_name("哈哈哈"); 错误,set_name不是常成员函数,不能调用
        cout << get_name() << endl;
        cout << name << endl;
//        name = "你好"; 错误
    }
};

string Test::get_name() const // 类外定义,即使声明的时候加了const,在定义时也要加const
{
    return name;
}

int main()
{
    Test t;
    t.set_name("再见");
    t.test_const();

    return 0;
}

一般只要成员函数不修改属性值就使用 const 修饰,以提高代码的安全性。

2》 修饰对象

const 修饰对象表示该对象时常量对象,这样的对象的成员变量数值不可变,不能调用任何非 const 修饰的成员函数。

cpp 复制代码
#include <iostream>

using namespace std;

class Test
{
public:
//    string name = "张三"; // 直接初始化可以

    string name;

//    Test(string name)
//    {
//        this->name = name; // 构造函数函数体初始化可以
//    }

    Test(string name):name(name){}

    void set_name(string name)
    {
        this->name = name;
    }

    string get_name() const
    {
        return name;
    }
};



int main()
{
    // const可以放在类型前后
    Test const t1("张三");
//    t1.set_name("你好"); 错误,set_name不是const修饰的函数,不可调用
    const Test t2("李四");
//    t2.name = "你好"; 错误
    cout << t1.get_name() << endl;
    cout << t2.get_name() << endl;

    return 0;
}

3》修饰成员变量

const 修饰的成员变量表示常成员变量,这样的成员变量不允许被修改。

常成员变量的初始化方式有两种:

1.直接初始化

2.构造初始化列表(优先级更高)

cpp 复制代码
#include <iostream>

using namespace std;

class Test
{
public:

    const string name = "张三"; // 直接初始化

    Test(){}
    Test(string name):name(name) // 构造初始化列表
    {}

//    Test(string name)
//    {
//        this->name = name; 错误
//    }

    void set_name(string name)
    {
//        this->name = name; 错误
    }

    string get_name() const
    {
        return name;
    }
};


int main()
{
    Test t0;
    cout << t0.get_name() << endl;
    Test t("王五");//由于初始化列表的优先级更高,所以"王五"覆盖掉了"张三"
    cout << t.get_name() << endl;

    return 0;
}

今天的分享就到这里结束啦,如果有哪里写的不好的地方,请指正。

如果觉得不错并且对你有帮助的话点个关注支持一下吧!

相关推荐
初遇你时动了情15 分钟前
uniapp 城市选择插件
开发语言·javascript·uni-app
程序猿小柒25 分钟前
leetcode hot100【LeetCode 4.寻找两个正序数组的中位数】java实现
java·算法·leetcode
雨中rain1 小时前
贪心算法(1)
算法·贪心算法
不爱学习的YY酱1 小时前
【操作系统不挂科】<CPU调度(13)>选择题(带答案与解析)
java·linux·前端·算法·操作系统
zongzi_4941 小时前
二次封装的天气时间日历选择组件
开发语言·javascript·ecmascript
平头哥在等你1 小时前
求一个3*3矩阵对角线元素之和
c语言·算法·矩阵
飞滕人生TYF1 小时前
动态规划 详解
算法·动态规划
kikyo哎哟喂1 小时前
Java 代理模式详解
java·开发语言·代理模式
_OLi_1 小时前
力扣 LeetCode 106. 从中序与后序遍历序列构造二叉树(Day9:二叉树)
数据结构·算法·leetcode
duration~1 小时前
SpringAOP模拟实现
java·开发语言