C++ 类(第二章)

C++ 类(第二章),第1张

文章目录
  • 前言
  • 一、C++ this指针
  • 二、静态成员变量
  • 三、静态成员函数
  • 四、const 成员变量、函数
  • 五、友元
  • 总结


前言

接着上一章继续讲一下this指针、静态成员、const成员和友元。


一、C++ this指针

this指针本质上是一个const指针,属于C++的关键字,可以默认指向当前对象,通过它可以访问当前对象的所有成员。因为this是一个指针,访问成员时需要使用 ->。我们使用this指针时需要知道以下几点知识:

  1. this指向当前对象,所以只有当对象创建后才能使用,所以静态成员函数不能使用this指针
  2. this指针只能用于成员函数中,用在其他地方没有意义
  3. this是const指针,不能修改

this指针可以理解为一个属于成员函数的隐式形参,只有通过对象调用时才会为其赋值,是成员函数的一个局部变量。

    class Demo{
    private:
        int a;
    public:
        void display(){
            cout<<this->a<<endl;
        };
    };

解释一下上述原因,C++函数编译时会根据命名空间、所属类、参数列表进行重命名,这个过程叫做命名编码,成员函数最终会被编译成与对象无关的全局函数,如果函数包含成员变量,编译成员函数时会新增一个参数,把当前对象指针传递进去,这个指针就是this指针,只不过平时是隐式的,也可以显示的调用。这样就完成了成员函数和成员变量的关联,因此在成员函数执行时,实际上是通过函数寻找对象。
参考:C++ 函数编译原理和成员函数的实现

二、静态成员变量

静态成员变量属于类本身,可以在多个对象之间共享,通过static关键字修饰,静态成员变量必须在类外进行初始化,因为静态成员不属于任何一个对象,所以不能通过构造函数进行初始化。调用时可以通过对象调用,也可以通过类名调用。

#include 
#include 
using namespace std;

class Animal{
    public:
        static int total;
    private:
        string name;
    public:
        Animal(string c_in):name(c_in){
            total++;
        }
        void show(){
            cout<<total<<endl;
        }
};

//静态成员变量必须在类外进行初始化
int Animal::total=0;

int main(){
    Animal cat("cat");
    Animal dog("dog");
    Animal pig("pig");

    cat.show();
    dog.show();
    pig.show();
    cout<<Animal::total<<endl;
    return 0;
}
  1. 静态成员变量和静态变量一样,内存都位于全局内存区,只有程序结束时释放。
  2. 静态成员变量在类外初始化时分配内存,如果未分配程序就会报错,静态成员变量不占用对象的内存。初始化时如果未赋值,会被默认初始化为0,因为全局区变量的默认初始值为0,栈和堆的默认值不确定。
  3. 静态成员变量的访问也要遵循private、protected、public规则,如果上面代码total为private,cout<就会报错。
  4. 静态成员变量属于类,只存在一份,无论哪一个对象访问,都是访问的同一个内存,所以static会被用于单例模式。
  5. 常量静态成员可以在类内进行初始化,但通常也应该在类外定义该成员。
    static constexpr int max=10
  6. 静态成员变量可以用作默认实参,也可以用于不完全类型,在平时估计很少用到。
class Bar{
public:
	...
private:
	static Bar mem1;//正确
	Bar *mem2;//正确
	Bar mem3;//错误
>};
三、静态成员函数

静态成员函数不与任何对象绑定,因此,不包含this指针,也不能被声明成const函数,所以静态成员函数只能访问静态成员变量和静态成员函数,非静态成员函数(普通成员函数、常成员函数)可以访问所有成员变量。静态成员函数可以在类内、也可以在类外定义。

#include 
#include 
using namespace std;

class Animal{
    private:
        static int total;
        string name;
    public:
        Animal(string c_in):name(c_in){
            total++;
        }
        static void show();
};

//静态成员变量必须在类外进行初始化
int Animal::total=0;
void Animal::show(){
    cout<<total<<endl;
}

int main(){
    Animal cat("cat");
    Animal dog("dog");
    Animal pig("pig");

    cat.show();
    dog.show();
    pig.show();
    Animal::show();

    return 0;
}

上面代码将show()定义为static,可以直接通过类访问。

四、const 成员变量、函数
  • const成员变量声明时只需增加const关键字,初始化时只能使用初始值列表进行初始化。

  • const成员函数声明时需要在头部结尾处加const,是int get() const; 而不是const int get(),第一个是常成员函数,只能读取任意一个成员变量但不能修改,第二个是返回一个int常量。const成员函数在声明和定义处都需要加const。

//常成员函数和变量
#include 
#include 
using namespace std;

class Animal{
private:
    string name;
    const string skin;
public:
    //skin只能通过初始值列表初始化
    Animal(string name, string skin):name(name),skin(skin){}
    //常成员函数只能读取属性
    void show() const;
};

void Animal::show() const{
    cout<<name<<"的毛色是"<<skin<<endl;
}

int main(){
    Animal cat("cat","red");
    cat.show();
}

const也可以声明对象,此时该对象被称为常对象,常对象只能访问常成员变量和常成员函数。

五、友元

友元是一个特别有意思的东西,它是单向,也不能被传递,通过友元可以打破private、protected、public的访问限制。例如函数A是类B的友元函数,则A可以访问B的私有数据成员。友元通过friend关键字修饰。

//友元函数和友元类
#include 
#include 
using namespace std;

class Animal{
private:
    string name;
    const string skin;
public:
    //skin只能通过初始值列表初始化
    Animal(string name, string skin):name(name),skin(skin){}
    //常成员函数只能读取属性
    friend void show(Animal *animal) ;
};

//
void show(Animal *animal){
    cout<<animal->name<<"的毛色是"<<animal->skin<<endl;
}

int main(){
    Animal cat("cat","green");
    show(&cat);//通过友元函数访问Animal类的私有成员变量
}

需要注意的因为show()是全局函数,所以不包含this指针,需要通过传入指针进行调用。一个类的成员函数也可以作为另一个类的友元函数。

//友元类
#include 
#include 
using namespace std;

class Country;

class Car{
private:
    string name;
    string skin;
public:
    Car(string name, string skin):name(name),skin(skin){}
    void show(Country *city);
};

class Country{
private:
    string city;
public:
    friend void Car::show(Country *city);
    Country(string city):city(city){}
};

void Car::show(Country *city){
    cout<<name<<"产自"<<city->city<<",颜色是"<<skin<<endl;
}


int main(){
    Country china("China");
    Car byd("byd","black");
    byd.show(&china);//通过Car的show问Country类的私有成员变量
}

整个类也可以被声明为友元,此时为友元类,该类的所有成员函数都是另一个类的友元函数,只要将friend void Car::show(Country *city);换为friend class Car;不过不建议这样做。

总结

基本上类的知识都已经讲完了把,接下来可以讲讲类的内存方面的知识。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/langs/1324006.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-06-12
下一篇2022-06-12

发表评论

登录后才能评论

评论列表(0条)