C++ static 与 const 的认识

柳随风
发布于 2020-9-4 10:00
浏览
0收藏

01 常量对象
如果不希望某个对象的值被改变,则定义该对象的时候可以在前面加const关键字

class CTest
{
public:
    void SetValue() {}
private:
    int m_value;
};

const CTest obj; // 常量对象

 

02 常量成员函数
在类的成员函数后面可以加const关键字,则该成员函数成为常量成员函数。

 

  • 在常量成员函数中不能修改成员变量的值(静态成员变量除外);
  • 也不能调用同类的 非 常量成员函数(静态成员函数除外)
class Sample
{
public:
    void GetValue() const {} // 常量成员函数
    void func(){}
    int m_value;
};

void Sample::GetValue() const // 常量成员函数
{
    value = 0; // 出错
    func();    // 出错
}

int main()
{
    const Sample obj;
    obj.value = 100; // 出错,常量对象不可以被修改
    obj.func(); // 出错,常量对象上面不能执行 非 常量成员函数
    obj.GetValue // OK,常量对象上可以执行常量成员函数
    
    return 0;
}

 

03 常量成员函数的重载
两个成员函数,名字和参数表都一样,但是一个是const,一个不是,那么是算是重载。

class Sample
{
public:
    Sample() { m_value = 1; }
    int GetValue() const { return m_value; } // 常量成员函数
    int GetValue() { return 2*m_value; } // 普通成员函数
    int m_value;
};

int main()
{
    const Sample obj1;
    std::cout << "常量成员函数 " << obj1.GetValue() << std::endl;
    
    Sample obj2;
    std::cout << "普通成员函数 " << obj2.GetValue() << std::endl;
}

执行结果:

常量成员函数 1
普通成员函数 2

 

04 常引用
引用前面可以加const关键字,成为常引用。不能通过常引用,修改其引用的变量的。

const int & r = n;
r = 5; // error
n = 4; // ok!

 

对象作为函数的参数时,生产该对象参数是需要调用复制构造函数的,这样效率就比较低。用指针作为参数,代码又不好看,如何解决呢?

 

可以用对象的引用作为参数,防止引发复制构造函数,如:

class Sample
{
    ...  
};

void Func(Sample & o) // 对象的引用作为参数
{
    ...
}

但是有个问题,对象引用作为函数的参数有一定的风险性,若函数中不小心修改了形参0,则实参也会跟着变,这可能不是我们想要的,如何避免呢?

 

可以用对象的常引用作为参数,如:

class Sample
{
    ...  
};

void Func(const Sample & o) // 对象的常引用作为参数
{
    ...
}

这样函数中就能确保不会出现无意中更改o值的语句了。

 

05 static 基本概念
静态成员:在定义前面加了static关键词的成员。

class A
{
public:
    A(int a, int b):m_a(a),m_b(b)
    {
        num += m_a + m_b;
    }
    
    ~A(){ }
    
    void Fun();             // 普通成员函数
    static void PrintNum()  // 静态成员函数
    {
        // 在静态成员函数中,不能访问非静态成员变量,也不能调用非静态成员函数
        std::cout << num << std::endl; 
    }
    
private:
    int m_a;         // 普通成员变量
    int m_b;         // 普通成员变量
    static int num;  // 静态成员变量
};

// 静态成员必须在定义类的文件中对静态成员变量进行初始化,否则会编译出错。
int A::num = 0;

int main()
{
    A a1(1,1);
    A::PrintNum(); // 访问静态函数
    A a2(1,1);
    A::PrintNum(); // 访问静态函数
    
    return 0;
}

输出结果

2
4

 

  • 普通成员变量每个对象有各自的一份,而静态成员变量一共就一份,为所有对象共享。

这里需要注意的是sizeof运算符不会计算静态成员变量的大小,如下例子:

class CTest
{
    int n;
    static int s;
};

则sizeof(CTest)等于4

 

  • 普通成员函数必须具体作用于某个对象,而静态成员函数并不具体作用于某个对象。
  • 因此静态成员不需要通过对象就能访问,因为他是共享的。

 

06 如何访问静态成员
1) 类名::成员名

A::PrintNum();

 

2) 对象名.成员名

A a;
a.PrintNum();

 

3) 指针->成员名

A *p = new A();
p->PrintNum();

 

4) 引用.成员名

A a;
A & ref = a;
ref.PrintNum();

 

07 static 小结

  • 静态成员变量本质上是全局变量,哪怕一个对象都不存在,类的静态成员变量也存在。
  • 静态成员函数本质上是全局函数。
  • 设置静态成员这种机制的目的是将和某些紧密相关的全局变量和函数写在类里面,看上去像是一个整体,易于维护和理解。
  • 在静态成员函数中,不能访问非静态成员变量,也不能调用非静态成员函数。
  • 静态成员必须在定义类的文件中对静态成员变量进行初始化,否则会编译出错。

 

分类
收藏
回复
举报
回复
    相关推荐