【C++】---static成员(附OJ题)

在这里插入图片描述

一、静态成员变量

1.概念:
声明为static类成员称为类的静态成员静态成员分为两种:

(1)static修饰的成员变量:静态成员变量

(2)static修饰的成员函数:静态成员函数


注意:静态成员变量一定要在:类外进行初始化

2.如何计算一个类里面定义了多少个对象?

#include<iostream>
using namespace std;
class A
{
public:
	A()
	{
		++countA;
	}
	A(const A& n)
	{
		++countA;
	}
	~A()
	{
		--countA;
	}
	// 静态成员函数 专门访问 静态成员变量
	static int GetCountA()
	{
		return countA;
	}
private:
	static int countA;// 静态成员变量在类内 只是 声明! 
					//这里的countA存在于静态区(全局域),它属于整个类的所有对象
};

int A::countA = 0; // (1)定义初始化:静态成员变量必须在类外,而且必须在 类 的后面!!!
				  // (2)定义的时候,不加static!
int main()
{
	cout << A::GetCountA() << endl;

	A a1, a2;
	A a3(a1);
	cout << A::GetCountA() << endl;

	return 0;
}

注意:类中的所有对象要么是构造出来的,要么是拷贝构造出来的!
因此我们需要定义一个全局的变量(生命周期也是全局的)才能满足我们的计算需求。
即:静态成员变量(出了作用域不销毁)

1.静态成员变量 必须在类外定义和初始化的原因

那么如何对它countA进行定义初始化呢?如果在类内初始化的话,那么会导致每个对象都包含该静态成员

静态成员变量 必须在类外定义和初始化的原因:

(1)声明不分配内存,只有定义才会分配内存,如果在类内定义静态成员变量的话,那么每个对象进行初始化时都要为静态变量分配一块空间,这样会导致重复定义。

(2)静态成员和类处于同一级别普通成员和对象处于同一级别。 类级别的成员,应先于类对象的存在而存在,且静态成员变量应被所有类对象共享,所以静态成员变量不能放在类内当对象初始化时才初始化。

2.如何在类外访问 静态成员变量

(1)突破类域:(去掉private,私有)让静态成员变量变为公有(很少用!)

#include<iostream>
using namespace std;
 
class A
{
public:
	A()//构造函数
	{
		++_n;
	}
 
	A(const A& a)//拷贝构造函数
	{
		++_n;
	}
 
//private:
	static int _n;//n存在于静态区,属于整个类,不属于某个对象
};
 
int A::_n = 0;
 
int main()
{
	A a1;
	A a2;
	A();
 
	//这三行访问的都是全局的_n,因此打印结果都一样
    cout << A::_n << endl;//类名::静态成员变量
	cout << a1._n << endl;//对象.静态成员变量
	cout << a2._n << endl;//对象.静态成员变量
}

(2)在类内专门写一个公有的函数来访问静态成员变量

#include<iostream>
using namespace std;
 
class A
{
public:
	A()//构造函数
	{
		++_n;
	}
 
	A(const A& a)//拷贝构造函数
	{
		++_n;
	}
 
	//获取静态成员变量的值
	int getN()
	{
		return _n;
	}
 
private:
	static int _n;//n存在于静态区,属于整个类,不属于某个对象
};
 
int A::_n = 0;
 
int main()
{
	A a1;
	A a2;
 
	//这两行访问的都是全局的_n,因此打印结果都一样
	cout << A().getN() << endl;
	cout << a1.getN() << endl;
	cout << a2.getN() << endl;
}

二、静态成员函数

静态成员函数跟普通的函数一模一样,静态成员函数没有this指针。静态成员函数只能访问静态成员变量,不能访问非静态成员!

因此一般定义一个静态成员函数来访问静态成员变量:

#include<iostream>
using namespace std;
class A
{
public:
	A()
	{
		++countA;
	}
	A(const A& n)
	{
		++countA;
	}
	~A()
	{
		--countA;
	}
	// 静态成员函数 专门访问 静态成员变量
	static int GetCountA()
	{
		return countA;
	}
private:
	static int countA;// 静态成员变量在类内 只是 声明! 
					//这里的countA存在于静态区(全局域),它属于整个类的所有对象
};

int A::countA = 0; // (1)定义初始化:静态成员变量必须在类外,而且必须在 类 的后面!!!
				  // (2)定义的时候,不加static!
int main()
{
	cout << A::GetCountA() << endl;

	A a1, a2;
	A a3(a1);
	cout << A::GetCountA() << endl;

	return 0;
}

三、static成员的特性

这些应该在理解的基础上 ,记忆背诵!

  1. 静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区
  2. 静态成员变量必须在类外定义定义时不加static在类中只是声明
  3. 静态成员函数没有隐藏的this指针不能访问任何非静态成员
  4. 类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问
  5. 静态成员也是类的成员受public、protected、private 访问限定符的限制

四、与static成员有关的OJ题

1.求1+2+3+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)OJ链接

解题思路:

(1)为了让函数执行n次,可以定义n个类对象,自动调用n次构造函数,在构造函数里面实现i自增和连续求和。

(2)为了使变量自增到n,使用i++,i不能作为成员变量,否则每个对象都有一个i,应该让所有对象都共享这个i,i应被定义成static。

class Sum
{
private:
    static int _i;
    static int _ret;
public:
    Sum()// 用构造函数实现_i的自增和_ret的连续求和!
    {
        _ret+=_i;
        ++_i;
    }
    static int Get_ret() // 静态成员函数 专门获取 静态成员变量_ret
    {
        return _ret;
    }
};

int Sum::_i=1;
int Sum::_ret=0;
class Solution 
{
public:
    int Sum_Solution(int n) 
    {
        Sum arr[n]; // 调用了n次构造函数
        return Sum::Get_ret();
    }
};

方法二:
内部类的应用:

class Solution 
{
    // class不写private 默认就是 私有
    // Sum是Solution的内部类,可以访问Solution的私有
    class Sum
    {
    public:
        Sum()
        {
            _ret+=_i;
            _i++;
        }
        // 因为Sum是Solution的友元,调用上面的默认构造函数时,我需要访问_ret和_i时,我可以直接访问solution的私有,
        // 所里这也不用,再定义一个静态函数。
        //static int GetN()
        //{   
        //    return _ret;
        //}
    };
private:
    static int _i;
    static int _ret;
public:
    int Sum_Solution(int n) 
    {
        Sum arr[n];// 数组arr调用n次Sum类的构造函数!
        return _ret;
    }
};
int Solution::_i=1;
int Solution::_ret=0;

2.计算日期到天数转换 :
oj链接

分析:
(1)数组不存放每月天数,而是存放1月1日到该月月底的天数;

(2)闰年要特殊处理

#include<iostream>
using namespace std;



int main()
{
	int year, month, day;
	int GetMonDay[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
	while (cin >> year >> month >> day)
	{
		int sum = 0;
		// 这里的循环 只加了当前的 整月份!(对day还没加上)
		for (int i = 0; i < month; i++)
		{
			sum = sum + GetMonDay[i];
		}
		if ((month > 2) && ((year % 4 == 0) && (year % 100 != 0)))
		{
			sum = sum + day + 1;
		}
		else
		{
			sum = sum + day;
		}
		cout << sum << endl;
	}
	return 0;
}

好了,今天的分享就到这里了
如果对你有帮助,记得点赞👍+关注哦!
我的主页还有其他文章,欢迎学习指点。关注我,让我们一起学习,一起成长吧!
在这里插入图片描述

  • 46
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 25
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小能软糖_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值