2022.9.28实训笔记

110 阅读6分钟

static

静态变量一个class内只有一份,内存中只有一份,所有对象共享

非静态属性对于每个对象,在内存中,都有自己的存储空间,各用各的,值可以不同

静态方法 调用时用类名调用,静态方法,不能访问this,当然也不能访问对象的任何属性,只能访问类属性(静态属性)

普通方法可以使用this访问自己

若需要两个对象之间可以共享数据,可以考虑使用静态变量

C++是适合编写大型复杂程序的语言,数据的共享与保护机制是C++的重要特性之一。

面向对象的程序设计方法兼顾数据的共享与保护,将数据与操作数据的函数封装在一起,构成集成度更高的组件或模块。同一个对象的数据成员可以被该对象的任何一个函数访问。对象与对象之间也需要共享数据,静态成员解决了同一个类的不同对象之间数据共享和函数共享的问题。

静态成员必须在定义类的文件中,在类外对静态成员变量进行初始化,否则会编译出错。

class Point {
public:
   Point(float x, float y):x(x),y(y){}
   Point(Point& p){
       printf("copy constructor:%x\n", &p);
       x = p.x;
       y = p.y;
   };
   void show(){
       printf("show:%x, x=%f, y=%f, K=%d\n", this, this->x, this->y, Point::K);
   }
   static int K;
private:
   float x, y;
};

int Point::K = 1;

int main() {
    Point p1(1, 1), p2(2, 2);
    p1.show();
    p2.show();
    Pont::K = 99;
    p2.show();
    p2.K--;
    p1.show();

    return 0;
}

生存期

如果对象的生存期与程序的运行期相同,则称它具有静态生存期。在命名空间作用域中声明的对象都是具有静态生存期的。如果要在函数内部局部作用域中声明具有静态生存期的对象,则要使用关键字static。局部作用域中的静态变量的特点是,它并不会随着每次函数调用而产生一个副本,也不会随着函数返回而失效。也就是说,当一个函数返回后,下一次再调用时,该变量还会保持上一回的值,即使发生递归调用,也不会为该变量建立新的副本,该变量在每次调用间共享。 注意:

static成员函数不包含this指针

static成员函数不能为virtual

不能存在static和non-static成员函数有相同的名字和参数

static 成员函数不能被声明成const、volatile或者const volatile

动态生存期

除上面两种情况,其余都是动态生存期。局部生存期对象诞于声明点,结束于声明所在的块执行完毕。 类的成员对象也有各自的生存期,不用static 修饰的成员对象,其生存期都与它们所属的对象生存期保持一致

作用域

一个标识符在程序中有效的范围。C++中标识符的作用域有函数原型作用域,局部作用域,类作用域和命名空间作用域。

命名空间

一个大型的程序通常由不同模块构成,不同模块甚至有可能由不同开发人员完成。不同模块中的类有可能发生重名,这样会引发错误。命令空间就像给类加了一个前缀,以示区别。

一个命名空间确定了一个命名空间作用域,凡是在该命名空间之内声明的,不属于前面所述的各个作用域的标识符,都属于该命名空间作用域。在一个命名空间中,要引用其它命名空间的标识符,可以采用下面的方式:

SomeNS :: SomeClass obj1; //声明一个SomeNS空间下的SomeClass类的对象obj1

有时,在标识符前使用这样的命名空间限定会显得过于冗长,为了解决这一问题,C++提供了using语句,有以下两种形式:

  1. using 命名空间::标识符;
  2. using namespace 命名空间;

前一种形式,将指定的标识符暴露在当前的作用域内,使得在当前作用域中可以直接引用该标识符 后一种形式,将指定命名空间的所有标识符暴露在当前的作用域内,使得在当前作用域中可以直接引用该命名空间内的任何标识符 事实上,C++标准程序库的所有标识符都被声明在s td命名空间下,前面用的cin, cout, endl都是如此,因此前面的程序都使用了 using namespace std; 如果去掉这条语句,则需要使用std::cin, std::cout这样的语法

全局空间和匿名命名空间

全局命名空间是默认的命名空间,在显式声明的命名空间之外声明的标识符都在一个全局命名空间中。匿名命名空间是一个需要显示声明的没有名字的命名空间,声明方式如下:

namespace { 各种声明 }

在包含多个源文件的工程中,匿名命名空间常常被用来隐藏不希望暴露给其它源文件的标识符。这是因为每个源文件的匿名命名空间是彼此不同的,在一个源文件中没有办法访问其他源文件的匿名命名空间。

友元函数

一个类是不能访问另一个类的私成成员的。友元关系提供了不同类或对象的成员函数之间,类的成员函数与一般函数之间进行数据共享的机制。

友元关系就是一个类主动声明哪些类或函数是它的朋友,进而给它们提供对本类的访问特许

在一个类中,可以利用关键字friend将其它函数或类声明为友元。如果友元是一般函数或类的成员函数,称为友元函数;如果友元是一个类,则称为友元类,友元类的所有成员函数都自动成为友元函数。

class Point {
public:
   Point(float x, float y):x(x),y(y){}
   Point(Point& p){
       printf("copy constructor:%x\n", p);
       x = p.x;
       y = p.y;
   };
   void show(){
       printf("show:%x, x=%f, y=%f\n", this, this->x, this->y);
   }
   friend float dist(Point &p1, Point &p2);
private:
   float x, y;
};

float dist(Point &p1, Point &p2){
    float x = p1.x - p2.x;
    float y = p1.y - p2.y;
    return sqrt(x*x + y*y);
}

int main() {
    Point p1(1, 1), p2(2, 2);
    cout << "The distance is: " << dist(p1, p2) << endl;
    return 0;
}

友元关系不能传递,友元是单向的,友元关系不能被继承

友元类示例 - 类的公有函数作为其它类的友元函数

不能将类的私有函数作为其它类的友元函数

常量

const 修饰的变量或成员不可修改;const修饰的函数在函数体内不可以修改任何变量值;const修饰引用,则指向的对象不能被修改。const修饰成员函数就是承诺不会修改该函数所属对象。

访问修饰符

public:在类的可见范围内,该成员可以被访问 protected:只允许子类及本类的成员函数访问 private:只允许本类的成员函数访问