第三课C++--之六 static

c++中的static作用

我们都知道c语言中的static的作用有两个:
1. 只初始化一次,而不会不停地初始化,相当于一个小的全局变量
2. 能够将变量的作用域限定在某个源文件中

在c++中的static主要是和类结合到一起的特性,但是它原来在c语言中的特性还是存在的以及c++中类的特性也还是存在的
1. 类中的static成员变量不属于对象,而是属于类的(我们可以使用类来直接操作我们的静态成员函数)
我们来看一个简单的例子,就可以知道了

class Demo
{
public:
    static int num_;    // 不属于对象的,属于类的
};
Demo::num_ = 100;

从上面的一个小示例中可以看出,我们可以通过类直接操作类中的公有属性的成员变量。
但是,如果我们把权限修改一下,如下所示

class Demo
{
private:
    static int num_;    // 不属于对象的,属于类的
};
Demo::num_ = 100;

那么此时就不会通过编译了,说明被static修饰后的类的成员变量还是具有原来c++中类的特性的。

再看下面的例子

class Demo
{
public:
    int num_;   // 不属于对象的,属于类的
};
Demo::num_ = 100;

我们把static去掉,此时编译也是不能通过的,因为num_是属于对象的。

还有一个冷知识,除了static int类型的变量能够在类中声明的时候就能初始化,其它类型的都不能这样做。

    // 可以初始化
    static const char c = 0;
    static const short s = 0;
    static const int count = 10;
    static const long l = 0;
    static const unsigned char uc = 0;
    static const unsigned short us = 0;
    static const unsigned int ui = 0;
    static const unsigned long ul = 0;

    // 不可以初始化
    const char c = 0;
    const short s = 0;
    const int count = 10;
    const long l = 0;
    const unsigned char uc = 0;
    const unsigned short us = 0;
    const unsigned int ui = 0;
    const unsigned long ul = 0;

    // 不可以初始化
    static const float f = 0.0;
    static const double d = 0.0;

其实,总的来说,整型的static const 变量可以直接在类里面初始化,其它的不可以,必须在类的外部初始化。

全局变量和类中的静态成员变量的区别
  1. 全局的变量到处都能改,而类中的静态成员变量可以告诉别人这个变量是属于哪一个类的,能够避免命名冲突。
  2. 能够实现封装的功能。
    特别需要注意的是静态成员变量的声明方式和初始化方式。

成员变量和成员函数

//.h文件
class Date
{
public:
    bool IsYear(int year);
privateint year_;
};

// .cpp文件
bool Date::IsYear(int year)
{
    return year % 100 == 0;
}

此时,我们不可以单独的使用这个Date类中的函数,我们必须实例化一个对象来使用这个函数,但是这样在使用方来说就变得有点复杂了。
如果我们在这个函数前面加上一个static的话,就可以通过类的作用域直接使用这个函数了。这样的成员函数就不再属于对象了,而是属于类了。

//.h文件
class Date
{
public:
    static bool IsYear(int year);
privateint year_;
};

// .cpp文件
bool Date::IsYear(int year)
{
    return year % 100 == 0;
}

但是这样又会出现一个问题,我们可以使用两种方式调用这个函数

/.h文件
class Date
{
public:
    static bool IsYear(int year);
privateint year_;
};

// .cpp文件
bool Date::IsYear(int year)
{
    return year % 100 == 0;
}


int main()
{
    Date demo;
    demo.IsYear(2017);
    Date::IsYear(2017);

    return 0;
}

毫无疑问,这两种方式都可以运行。但是从编程规范来说,使用对象来调用静态成员函数是不对的,因为静态成员函数中是没有this指针的,即没有对象属性。

//.h文件
class Date
{
public:
    static bool IsYear(int year);

private:
        int year_;
};

// .cpp文件
bool Date::IsYear(int year)
{
    this->year_ = 10;
    return year % 100 == 0;
}


int main()
{
    Date demo;
    demo.IsYear(2017);
    Date::IsYear(2017);

    return 0;
}

会有这样的错误:
error C2355: “this”: 只能在非静态成员函数或非静态数据成员初始值设定项的内部引用,也就意味着不能访问非静态成员变量,它只能访问静态成员变量。

//.h文件
class Date
{
public:
    static bool IsYear(int year);

private:
    int year_;
    static int num_;
};

int Date::num_ = 10;

// .cpp文件
bool Date::IsYear(int year)
{
    num_ = 100;
    return year % 100 == 0;
}


int main()
{
    Date demo;
    demo.IsYear(2017);
    Date::IsYear(2017);

    return 0;
}

费静态成员函数可以访问静态成员变量

//.h文件
class Date
{
public:
    static bool IsYear(int year);   // 不属于对象,属于类
    int GetNum();                   // 费静态成员却能够访问静态成员

private:
    int year_;
    static int num_;
};

int Date::num_ = 10;

// .cpp文件
bool Date::IsYear(int year) // 没有this指针 没有对象属性的
{
    // 不能访问非静态成员
    num_ = 100;
    return year % 100 == 0;
}

int Date::GetNum()
{
    return num_;
}


int main()
{
    Date demo;
    demo.IsYear(2017);
    Date::IsYear(2017);

    return 0;
}

虽然能够运行,但是严格来说,这样也是不对的,跟上面的错误原因一样。,如果我们要获得一个静态成员变量,那么它就应该是一个静态的成员函数。

//.h文件
class Date
{
public:
    static bool IsYear(int year);   // 不属于对象,属于类
    static int GetNum();            // 费静态成员却能够访问静态成员

private:
    int year_;
    static int num_;
};

int Date::num_ = 10;

// .cpp文件
bool Date::IsYear(int year) // 没有this指针 没有对象属性的
{
    // 不能访问非静态成员
    num_ = 100;
    return year % 100 == 0;
}

int Date::GetNum()
{
    return num_
}


int main()
{
    Date demo;
    demo.IsYear(2017);
    Date::IsYear(2017);

    return 0;
}
问题:类里面的静态成员函数和静态成员变量受不受访问权限的控制呢?

答案是肯定的,这是因为:
首先,它是一个类成员
其次,它是类的静态成员,所以受访问权限的控制

关于类中的static特性总结如下:

成员变量:
1. 被所有对象共享的,但是它不属于对象,而是属于类的。(后面的度线程还要被static坑一次)
2. 通过类名直接访问(当然,也可以用对象来访问,虽然这种访问方式在语法上说得过去,但是在编程规范上就不符合了 )
3. 被所有对象共享的,但是它不属于对象,而是属于类的。(后面的度线程还要被static坑一次)
static成员变量是不占用类空间的,可以使用sizeof验证。
成员函数:
成员函数:
1. 没有this指针,意味着无法访问非静态成员(包括变量和函数)

单例模式

// 有的时候,我们只需要一份,比如说计数器
// 单例模式
// 1. 无法初始化
// 2. 能够获取一个对象
// 3. 
class Counter
{
public:
    //static Counter &GetInstance()
    //{
    //  static Counter demo;    // 只会被初始化一次
    //  return demo;
    //}
    static Counter *GetInstance()
    {
        if (!demo)
        {
            demo = new Counter;
        }
        return demo;
    }

    ~Counter()
    {
        std::cout << "~Counter()" << std::endl;
    }

private:
    Counter()
    {
        std::cout << "Counter()" << std::endl;
    }
    Counter(const Counter &){}
    Counter &operator=(const Counter &otehr){}
    static Counter *demo;
};

Counter *Counter::demo;

int main()
{
    //Counter &demo = Counter::GetInstance();

    Counter *demo1 = Counter::GetInstance();
    Counter *demo2 = Counter::GetInstance();
    Counter *demo3 = Counter::GetInstance();

    return 0;
}

运行结果如下:
这里写图片描述
只实例化了一个对象,但是对象始终没有析构,这是因为没有delete,我们再写一个释放对象的函数。

// 有的时候,我们只需要一份,比如说计数器
// 单例模式
// 1. 无法初始化
// 2. 能够获取一个对象
// 3. 
class Counter
{
public:
    //static Counter &GetInstance()
    //{
    //  static Counter demo;    // 只会被初始化一次
    //  return demo;
    //}
    static Counter *GetInstance()
    {
        if (!demo)
        {
            demo = new Counter;
        }
        return demo;
    }

    static void Free()
    {
        delete demo;
    }

    ~Counter()
    {
        std::cout << "~Counter()" << std::endl;
    }

private:
    Counter()
    {
        std::cout << "Counter()" << std::endl;
    }
    Counter(const Counter &){}
    Counter &operator=(const Counter &otehr){}
    static Counter *demo;
};

Counter *Counter::demo;

int main()
{
    //Counter &demo = Counter::GetInstance();

    Counter *demo1 = Counter::GetInstance();
    Counter *demo2 = Counter::GetInstance();
    Counter *demo3 = Counter::GetInstance();

    Counter::Free();

    return 0;
}

运行结果如下:
这里写图片描述

这样看起来似乎很完美,但是,当我们的工程变大的时候,我们是不知道在哪里释放的,这样会出问题。
我们可以使用内部类和智能指针来实现对象的释放。
但是对于目前来说,还是我们的第一种方法最合适。

C++中的const特性

  1. const对象只能访问const的函数
  2. const函数和非const函数可以构成重载
  3. 我们在写类中的const和非const版本的时候,是有一个约定俗成的规则的,就是非const版本调用const版本。
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
回答: 在C++中,static关键字主要用于限定对象所使用的内存区域。根据static所应用对象的不同,可以分为全局对象、本地静态对象和类静态成员。在全局变量中使用static关键字,可以将变量存储在静态存储区,使得在函数调用完成后不会释放变量。相比之下,如果没有static修饰符,变量在函数重新被调用时会被再次初始化。\[2\]举个例子,假设有以下代码: ```cpp #include <iostream> using namespace std; int foo1(void){ static int i = 10; return i++; } int foo2(void){ int j = 10; return j++; } int main(void){ cout << "第一次 foo1()=" << foo1() << endl; cout << "第一次 foo2()=" << foo2() << endl; cout << "第二次 foo1()=" << foo1() << endl; cout << "第二次 foo2()=" << foo2() << endl; return 0; } ``` 在这个例子中,foo1()函数中的变量i被声明为静态变量,所以每次调用foo1()函数时,i的值会递增。而foo2()函数中的变量j没有被声明为静态变量,所以每次调用foo2()函数时,j的值都会重新初始化为10。\[3\]这就是C++static关键字的用法。 #### 引用[.reference_title] - *1* *3* [C++ 语法篇之 static 用法](https://blog.csdn.net/yixiwuha/article/details/123145702)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [C++ static用法总结](https://blog.csdn.net/kupe87826/article/details/121310136)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值