- 面对对象编程技术的一个重要特征是用一个对象把数据和对数据处理的方法封装在一起。
- 在前边的例子里我们一直是在使用对象(也可以说某个类的实例)来调用方法,每个方法只处理调用它的那个对象所包含的数据,所有的数据都属于同一个对象。
这就引发了一个问题:如果我们所需要的功能或数据不属于某个特性的对象,而是属于整个类的,该怎么办?
- 创建全局变量,任何代码都可以修改这个变量,不小心会出事。(非必要不建议)
- 使用静态属性或静态方法
1.使用静态属性或静态方法的好处
C++ 允许我们把一个或多个成员声明为属于某个类,而不是仅属于该类的对象。(就是说这个成
员仅能让该类调用)
- 这么做的好处是程序员可以在没有创建任何对象的情况下调用有关的方法。
- 另外一个好处是能够让有关的数据仍在该类的所有对象间共享。
方法:创建一个静态属性或静态方法
2.创建、访问 静态属性或静态方法:
创建:只需要在它的声明前加上 static 保留字即可。
访问:类名::静态属性或静态方法
类的对象.静态属性或静态方法(不建议)
3.静态属性和静态方法的介绍
在 C++ 里,静态属性和方法属于类,而不是类的实例。
- 静态属性:被类的所有实例共享,它在类的所有对象间仅有一个副本(即无论创建了多少个类的对象,静态属性只有一份副本,被所有对象共享)。
- 你需要在类的定义里声明静态属性,并且在类的外部对其进行初始化。
- 静态局部变量是在函数内部使用
static
关键字声明的变量,若不进行显式初始化,静态局部变量会被自动初始化为默认值0- 静态成员变量在类内部声明,在类外部定义和初始化。若不在类外部进行显式初始化,程序会无法通过链接。
- 常用于记录与类相关的全局信息,例如对象的创建数量、共享的资源等。
静态方法:只能访问静态属性和其他静态方法,不能访问非静态成员,因为非静态成员和具体的对象实例相关联。
- 静态方法不依赖于任何对象,因此在调用时不需要创建类的对象。
- 静态方法在类的内部声明时需要使用
static
关键字,定义可以在类内也可以在类外。- 常用于实现与类相关的工具函数,这些函数不依赖于对象的状态,例如数学计算、文件操作等。
#include <iostream>
class MyClass {
public:
// 声明静态属性
static int staticAttribute;
// 声明静态方法:此方法能访问静态属性staticAttribute。
static void staticMethod() {
std::cout << "静态属性的值为: " << staticAttribute << std::endl;
}
};
// 在类的外部初始化静态属性
int MyClass::staticAttribute = 10;
int main() {
// 直接通过类名访问静态属性和方法
MyClass::staticAttribute = 20;
MyClass::staticMethod();
return 0;
}
4.案例
#include <iostream>
#include <string>
class Pet
{
public:
Pet(std::string theName);
~Pet();
static int getCount();
protected:
std::string name;
private:
static int count;
};
class Dog:public Pet
{
public:
Dog(std::string theName);
};
class Cat:public Pet
{
public:
Cat(std::string theName);
};
int Pet::count=0; //注意这一句:做了两件事 ---1.让编译器为count这个变量的值分配内存 。2.把这个变量(在静态存储区)初始化为0
Pet::Pet(std::string theName)
{
name=theName;
count++;
std::cout<<"一只宠物出生了,名字叫做:"<<name<<"\n";
}
Pet::~Pet()
{
count--;
std::cout<<name<<"挂掉了\n";
}
int Pet::getCount()
{
return count;
}
Dog::Dog(std::string theName):Pet(theName){}
Cat::Cat(std::string theName):Pet(theName){}
int main()
{
Dog dog("Tom");
Cat cat("Jerry");
std::cout<<"\n已经诞生了"<<Pet::getCount()<<"只宠物!\n\n";
// {}可以认为是一个区域 ,当程序执行到代码块开始处时,dog2 和 cat2 对象被创建,代码块结束时,dog2 和 cat2 被销毁
{
Dog dog2("Tom2");
Cat cat2("Jerry2");
std::cout<<"\n已经诞生了"<<Pet::getCount()<<"只宠物!\n\n";
}
std::cout<<"现在还剩下"<<Pet::getCount()<<"只宠物!\n\n";
return 0;
}
当程序执行到代码块开始处时,dog2
和 cat2
对象被创建,调用 Dog
和 Cat
类的构造函数,Pet
类的静态成员变量 count
加 2。当程序执行完代码块时,dog2
和 cat2
对象的生命周期结束,调用它们的析构函数,Pet
类的静态成员变量 count
减 2。
#include <iostream>
#include <string>
class Pet
{
public:
Pet(std::string theName);
~Pet();
static int getCount();
protected:
std::string name;
private:
static int count;
};
class Dog:public Pet
{
public:
Dog(std::string theName);
};
class Cat:public Pet
{
public:
Cat(std::string theName);
};
int Pet::count=0; //注意这一句:做了两件事 ---1.让编译器为count这个变量的值分配内存 。2.把这个变量(在静态存储区)初始化为0
Pet::Pet(std::string theName)
{
name=theName;
count++;
std::cout<<"一只宠物出生了,名字叫做:"<<name<<"\n";
}
Pet::~Pet()
{
count--;
std::cout<<name<<"挂掉了\n";
}
int Pet::getCount()
{
return count;
}
Dog::Dog(std::string theName):Pet(theName){}
Cat::Cat(std::string theName):Pet(theName){}
int main()
{
Dog dog("Tom");
Cat cat("Jerry");
std::cout<<"\n已经诞生了"<<Pet::getCount()<<"只宠物!\n\n";
//不加 {}:dog2 和 cat2 会一直存活到 main 函数结束,所以在后续输出时,count 不会减少。
{
Dog dog2("Tom2");
Cat cat2("Jerry2");
std::cout<<"\n已经诞生了"<<Pet::getCount()<<"只宠物!\n\n";
}
std::cout<<"现在还剩下"<<Pet::getCount()<<"只宠物!\n\n";
return 0;
}
dog2
和 cat2
对象在 main
函数中被创建后,它们的生命周期会一直持续到 main
函数结束。只有当 main
函数执行完毕时,才会调用它们的析构函数,Pet
类的静态成员变量 count
才会减 2。
未完待续。。。