C++类的拓展

1、类成员存储(class member storage)

对于类的大小,发现成员函数并不用类的存储空间。
只用一段空间来存放这个共同的函数代码段,在调用各对象的函数时,都去调用这个公用的函数代码。
所有的对象都调用共用的函数代码段,如何保证访问的是调用对象的成员呢?为此,C++设置了 this 指针,对象在调用公用函数时,并将对象的指针作为隐含参数传入其内,从而保证了访问的成员,属于调用者。

2、const 修饰类

const修饰数据成员

const 修饰数据成员,称为常数据成员,可能被普通成员函数和常成员函数来使用,不可以更改。必须初始化,可以在类中,也就是在类中定义这个变量的同事初始化(不推荐),或初始化参数列表中(这是在类对象生成之前唯一一次改变 const 成员的值的机会了)。
不可以在构造器中初始化,只能是初始化参数列表中初始化。否则报错

const修饰成员函数

const修饰成员函数承诺在本函数内部不会修改类内的数据成员,为此,也只能调用承诺不会改变成员的其它 const 成员函数,而不能调用其它非 const 成员函数。

const 修饰函数放在,声明之后,实现体之前,大概也没有别的地方可以放了。

void dis() const
{
    
}

const修饰成员函数注意要点

const 修饰函数,在声明之后,实现体之前。

const 函数只能调用 const 函数。非 const 函数可以调用 const 函数。

如果 const 构成函数重载,const 对象只能调用 const 函数,非 const 对象优先调用非 const 函数。

类体外定义的 const 成员函数,在定义和声明处都需要 const 修饰符(有些关键字是定义型的,有些是声明型的)。

3、static 修饰类

C++扩展了 static 在类中的语意,用于实现在同一个类,多个对象间数据共享,协调行为的目的。静态变量有全局变量的优势,又不会像全变量一样被滥用。而这一类变量,即可以通过类来管理,也可以通过类的静态函数来管理。类的静态成员,属于类,也属于对象,但终归属于类。

static修饰数据成员

static修饰的数据成员声明在类内部,然后要在类外部初始化,既可以通过对象也可以通类访问(类访问也得是public才能访问)。static 成员使用时必须初始化,且只能类外初始化。声明与实现分离时,只能初始化在实现部分(cpp 部分)。注意这个static这个关键字只能放在类的声明处,也就是类里边,在外部初始化的时候不要写这个关键字。就像下面的代码一样:

#include <iostream>
using namespace std;
class A
{
public:
    void foo()
    {
        cout<<"void foo"<<endl;
        share++;
    } 
private:
    static int share; //static修饰数据成员
};

int A::share = 0;  //类外实现初始化,如果类分为.h和.cpp.这行代码写到.cpp中

static修饰的数据成员可以在所有的对象中共享数据,比如一个对象改了static修饰的数据成员变量,那么别的对象访问的时候也就是前一个对象修改了的数据

static 修饰成员函数

为了管理静态成员,C++提供了静态函数,以对外提供接口。并且静态函数只能访问静态成员。不能调用其他成员,包括成员函数和其他的非static数据成员。

在类内部函数的声明和定义,就按照下面的方法实现

static int fooInvokeCount() //只能访问静态成员,不能访问别的数据成员
{
    
}

静态成员函数只能访问静态数据成员。原因:非静态成员函数,在调用时 this指针时被当作参数传进。而静态成员函数属于类,而不属于对象,没有 this 指针。

4、static const 类型

如果一个类的成员,既要实现共享,又要实现不可改变,那就用 static const 组合模式来修饰。修饰成员函数,格式并无二异,修饰数据成员,必须要类内部初始化。

5、指向类成员的指针

C++扩展了指针在类中的使用,使其可以指向类成员(数据成员和函数成员),这种行为是类层面的,而不是对象层面的。

指向类数据成员的指针

指向类数据成员的指针其实并没有多大的意义,因为数据成员一般都是private的,只有类的数据成员是public的时候才有意义。不过我们也来说说。

声明<数据类型><类名>::*<指针名>
初始化<数据类型><类名>::*<指针名>=& <类名>::<非静态数据成员>
解引用<类对象名>.*<指向非静态数据成员的指针>
<类对象指针>->*<指向非静态数据成员的指针>

实例:

#include <iostream>
using namespace std;
class Student
{
public:
    Student(string n, int nu):name(n),num(nu){}
    string name;
    int num;
};
int main()
{
    Student s("zhangsan",23);
    
    string Student::*pn = &Student::name; //指向类数据成员的指针  就这么定义
    cout<<s.*pn<<endl;                      //解引用
    
    Student *ps = new Student("zhaoliu",35); 
    cout<<ps->*pn<<endl;
    return 0;                                //解引用
}

指向类成员函数的指针

定义一个指向非静态成员函数的指针必须在三个方面与其指向的成员函数保持一致:参数列表要相同、返回类型要相同、所属的类型(类名)要相同。
由于类不是运行时存在的对象。因此,在使用这类指针时,需要首先指定类的一个对象,然后,通过对象来引用指针所指向的成员。

声明<数据类型>(<类名>::*<指针名>)(<参数列表>)
初始化<数据类型>(<类名>::*<指针名>)(<参数列表>)=&<类名>::<非静态成员函数>
解引用(<类对象名>.*<指向非静态成员函数的指针>)(<参数列表>)
(<类对象指针>->*<指向非静态成员函数的指针>)(<参数列表>)

实例:

#include <iostream>
using namespace std;
class Student
{
public:
    Student(string n, int nu):name(n),num(nu){}
    void dis()
    {
        cout<<"name:"<<name<<" num:"<<num<<endl;
    }
private:
    string name;
    int num;
};
int main()
{
    Student s("zhangsan",23);
    Student *ps = new Student("zhaoliu",35);
    
    void (Student::*pf)() = Student::dis;//指向类函数成员的指针  就这么定义,注意括号包起来::
    (s.*pf)();//解引用

    (ps->*pf)();//解引用
    return 0;
}

指向类静态成员的指针

指向静态成员的指针的定义和使用与普通指针相同,在定义时无须和类相关联,在使用时也无须和具体的对象相关联。

指针指向类成员变量数据成员

声明<数据类型>*<指针名>
初始化<数据类型>*<指针名>=& <类名>::<静态数据成员>
解引用(*<指向静态数据成员的指针>)

指针指向类函数成员

声明<数据类型>(*<指针名>)(<参数列表>)
初始化<数据类型>(*<指针名>)(<参数列表>)=&<类名>::<静态成员函数>
解引用(*<指向静态成员函数的指针>)(<参数列表>)

不举例子了。

Last modification:October 6th, 2019 at 02:12 pm
如果觉得我的文章对你有用,请随意赞赏

Leave a Comment