c++静态成员变量和静态成员函数

#define _CRT_SECURE_NO_WARNINGS

#include<iostream>

using namespace std;

//静态成员函数与静态变量不需要通过创建对象来开辟空间,在类里声明的时候就已经在静态区域开辟空间了
//静态成员变量不在类的内部空间,在类的外部静态区中,所以计算类的大小时,是不包含静态成员变量的空间大小的
//而非静态成员变量必须通过创建对象来开辟空间,对象包含着非静态成员变量
//当对象还没有创建时,即非静态成员还没有被实例化,但此时静态方法已经被创建,如果这时候去访问非静态变量时访问不到的,因为这个非静态变量此时根本就不存在
//因此静态成员函数只能访问静态成员变量,普通成员函数可以访问普通成员变量和静态成员变量
class AA
{
public:
    AA(int a, int b) :my_c(10)
    {
        my_a = a;
        my_b = b;
    }

    //static修饰的静态成员变量在静态空间开辟空间,只初始化一次
    //类里的一般变量在对象内部,但static修饰的静态变量不在对象内部,仍单独在静态区域开辟空间,这个类可以有多个对象,静态变量不属于某一个对象,所有对象共同持有它
    //因此在类的内部不可以直接为静态变量赋值,例:static int my_d = 10;这种写法是完全错误的
    static int my_d;

    int &getA()
    {
        return my_a;
    }
    //&getE方法返回的是私有成员变量my_e的引用(即地址),可以做左值,这时候表示为引用,为私有变量my_e赋值;也可以做右值,这时候表示为值,给别的变量赋值
    int &getE()
    {
        return my_e;
    }
    //&getEE同理&getE,&getE能力包含&getEE
    static int &getEE()
    {
        return my_e;
    }
    //非引用返回,只能做为右值,为别的变量赋值
    int getEEE()
    {
        return my_e;
    }
    void change(int e)
    {
        my_e = e;
    }
    
private:
    int my_a;
    int my_b;
    const int my_c;//就算是常量也只能声明,仍没有开辟内存空间
    static int my_e;//当静态成员变量在私有空间时,仍在类的外部加命名空间进行初始化赋值,但只可以初始化,其他在类的外部的访问都是不可以的
};
//类里的静态成员变量一定要在类的外部初始化赋值,这是不用加static关键字,但需要加命名空间,表示my_d是哪个空间的,使编译器找到my_d的位置,防止发生歧义
int AA::my_d = 10;
int AA::my_e = 100;

//表示函数作用域只在本文件,其他文件不可调用这个静态函数
//函数的本质是实现一个特定功能的一段代码,这段代码是直接运行的,如果这段代码用到变量,则需要分配内存空间,代码存储在代码空间,变量存储在存储空间
static void test()
{
    cout << "hello world" << endl;
}

//类里静态变量与常量的区别
class BB
{
public:
    BB() :b(10)//但类里的常量一定要用构造函数初始化列表进行初始化,这样就满足了常量初始化时一定要赋值的要求
    {
        
    }
private:
    static int a;//静态变量是在声明类的时候就已经创建了,这时候还没有类的对象,且静态变量属于这个类的所有对象,存储空间在静态区域中
    const int b;//const修饰变量的时候,变量变为常量,一定要初始化,但这儿只是定义类,还没有为变量开辟空间,所以类里的常量可以先声明
};
//但静态变量一定要早类的外面进行初始化赋值,不能在类的里面,因为静态变量属于所有对象,属于类,不属于单个对象,初始化时不用加static关键词,但要加类的作用域(命名空间???)
int BB::a = 10;


class Box
{
public:
    Box(int len, int width)
    {
        my_len = len;
        my_width = width;
    }
private:
    int my_len;
    int my_width;
    //这种定义方式就表示了Box每个对象的高确定,长和宽需要手动去设置,即static静态变量的一个实际意义
    static int hight;
};
int Box::hight = 10;

//空间占用分布
//1.这种是典型的占用8字节空间
class Test1
{
public:
    int a;
    int b;
private:
};
//2.这种类型占用8字节空间,静态变量不在类内部,所以不占用类的空间
class Test2
{
public:
    int a;
    int b;
    static int c;
private:

};
int Test2::c = 10;
//3.这种类型占用的是8字节空间,函数是不占类的内部空间的,函数统一存储在代码区中
class Test3
{
public:
    void create()
    {
        cout << "hello world" << endl;
    }
private:
    int a;
    int b;
};

//拷贝构造应用场景
//1.
class Func
{
public:
    Func(int a, int b)
    {
        my_a = a;
        my_b = b;
    }
    //只有左面为数据类型的&才为引用
    Func(const Func &another)
    {
        cout << "copy function" << endl;
    }
private:
    int my_a;
    int my_b;
};

//拷贝函数应用场景
Func function1()
{
    Func func(10, 20);
    //return的时候调用的拷贝构造函数,新建了一个匿名对象,并把对象func的值赋给了此匿名对象,在这个函数的生命周期一共是建了两个对象
    return func;//这儿会创建一个匿名对象,因为对象func的生命周期与函数的生命周期相同,当function()函数结束时,对象func也被回收了,此时return返回func对象是不存在的,因此需要新建一个匿名对象当做返回值
}
//类的对象的返回好像和常规变量的返回不同,变常规量是不存在拷贝构造函数的
int function2()
{
    int a = 10;
    return a;
}

int main()
{
    int a, b, c;
    c = 0;
    a = c++;//先赋值,再加加
    cout << "a=" << a << endl << "c=" << c << endl;

    AA a1(1, 2);
    //静态变量可以有两种访问方式,一种是对象持有访问,第二种是因为静态成员变量属于类(类相当于一个命名空间???),因此可以用类直接访问
    a1.my_d = 10;
    AA::my_d = 20;

    a1.getA() = 10;
    a1.getE() = 10;
    b = a1.getE();

    //静态方法有两种调用方法,一种是通过对象调用静态方法,另一种是通过类的命名空间直接调用静态方,因为静态方法在类声明时就已经建立了
    a1.getEE() = 20;
    AA::getEE() = 20;

    //类的常规函数对类的私有静态成员变量操作与静态方法效果一样
    a1.change(10000);
    cout << "my_e=" << a1.getEEE() << endl;

    //new和delete一样,返回的是地址,所以需要指着去接收
    Box *box = new Box(10, 20);
    delete box;

    //下面三段代码的结果都是一样的,都是8
    cout << "Test1=" << sizeof(Test1) << endl;
    cout << "Test2=" << sizeof(Test2) << endl;
    cout << "Test3=" << sizeof(Test3) << endl;

    //下面一段代码是返回了一个匿名对象,当一个函数返回一个匿名对象的时候,函数外部没有任何变量去接收它时,这个匿名对象将不再被使用(因为根本找不到),编译器会直接将这个匿名对象回收掉,而不是等待整个程序执行完再回收
    function1();
    //当有对象接收匿名对象时,如果是在初始化阶段,如下面一段代码,会直接把这个匿名对象命名为func1
    Func func1 = function1();
    //下面两段代码的意思是,先建立的对象func2,func2去接收了匿名对象,当不是调用了拷贝构造函数,只是直接的赋值操作,此时匿名对象会被编译器立刻回收掉
    Func func2(1, 2);
    func2 = function1();

    b = function2();
    cout << "function2=" << b << endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/tulipless/article/details/80498339