【C++笔记总结】面向对象编程——封装 |C++

news2024/11/24 17:58:42

文章目录

  • 前言
  • 一、类的封装
    • 1.1、公有,私有,保护
    • 1.2、类的定义和类的实现相分离
    • 1.3、构造函数,析构函数,拷贝构造函数
    • 1.4、静态数据成员和静态成员函数
    • 1.5、友元函数,友元类
  • 二、类的实现——对象
    • 2.1、对象的静态分配,动态分配(堆对象)
    • 2.2、子对象
    • 2.3、this指针


前言

此文开启一个系列,旨在秋招前将所有C++笔记进行汇总总结。
参考答案:chatgpt

一、类的封装

1.1、公有,私有,保护

类中的数据称之为数据成员,类中的函数称之为成员函数
在C++中,类的成员变量和成员函数可以被访问控制符所限制,这些访问控制符分别是公有(public)、保护(protected)和私有(private)。举例1.1如下:

#include <iostream>

class MyClass {
public:
    void setData(int shuru) {
        privateData = shuru; // 类内使用私有成员:将参数赋值给私有成员
        protectedData = shuru * 2; // 类内使用保护成员:将参数的两倍赋值给保护成员
        std::cout << "setData: privateData = " << privateData << ", protectedData = " << protectedData << std::endl;
        // 在类的成员函数中访问保护成员和私有成员
        privateFunc();
        protectedFunc();
    }
    int getData() {
        return privateData; // 类内使用私有成员::直接使用私有成员的名称
    }

protected:
    int protectedData; // 保护成员
    void protectedFunc() {
        std::cout << "This is a protected function." << std::endl;
    } // 保护成员函数

private:
    int privateData; // 私有成员
    void privateFunc() {
        std::cout << "This is a private function." << std::endl;
    } // 私有成员函数
};

int main() {
    MyClass obj;//对象
    obj.setData(1234);//公有方法,可以在类外访问
    std::cout << "Data: " << obj.getData() << std::endl; 公有方法,可以在类外访问

    // obj.privateData = 456; // 私有成员不能在类的外部访问
    // obj.privateFunc(); // 私有函数不能在类的外部访问
    // obj.protectedData = 789; // 不能在类的外部访问保护成员
    // obj.protectedFunc(); // 保护函数不能在类的外部访问

    return 0;
}

1)公有成员函数可以在类的外部访问;私有成员函数和保护成员函数不能在类的外部访问,只能在类的内部访问。相当于是类的外部接口。
2)私有成员和保护成员的区别在于,私有成员只能在当前类的成员函数中访问,保护成员可以在当前类的成员函数和派生类的成员函数中访问。
3)公有成员函数可以访问类的所有成员,私有成员函数和保护成员函数也可以访问类的所有成员。

1.2、类的定义和类的实现相分离

在大型的C++工程文件里,类的定义和实现经常这样分开:(下面分成了三个文件)
MyClass.h:

MyClass.h:
#ifndef MYCLASS_H
#define MYCLASS_H

class MyClass {
public:
    void setData(int shuru);
    int getData();

protected:
    int protectedData;
    void protectedFunc();

private:
    int privateData;
    void privateFunc();
};

#endif

MyClass.cpp:

MyClass.cpp:
#include "MyClass.h"
#include <iostream>

void MyClass::setData(int shuru) {
    privateData = shuru; // 类内使用私有成员:将参数赋值给私有成员
    protectedData = shuru * 2; // 类内使用保护成员:将参数的两倍赋值给保护成员
    std::cout << "setData: privateData = " << privateData << ", protectedData = " << protectedData << std::endl;
    // 在类的成员函数中访问保护成员和私有成员
    privateFunc();
    protectedFunc();
}

int MyClass::getData() {
    return privateData; // 类内使用私有成员::直接使用私有成员的名称
}

void MyClass::protectedFunc() {
    std::cout << "This is a protected function." << std::endl;
} // 保护成员函数

void MyClass::privateFunc() {
    std::cout << "This is a private function." << std::endl;
} // 私有成员函数

main.cpp:

main.cpp:
#include <iostream>
#include "MyClass.h"

int main() {
    MyClass obj;
    obj.setData(1234);
    std::cout << "Data: " << obj.getData() << std::endl;

    // obj.privateData = 456; // 私有成员不能在类的外部访问
    // obj.privateFunc(); // 私有函数不能在类的外部访问
    // obj.protectedData = 789; // 不能在类的外部访问保护成员
    // obj.protectedFunc(); // 保护函数不能在类的外部访问

    return 0;
}

这样做的好处有很多:
1)使代码更加清晰和易于维护。类的界面和实现分开,可以更加清晰地区分哪些是公共接口,哪些是实现细节,方便用户和开发人员理解和使用。
2)提高代码的可重用性。将类的实现与界面分离,可以方便地将类的实现部分复用到其他项目中,而不必担心可能引入的冲突和问题。
3)增加代码的安全性。将类的实现细节隐藏起来,可以防止外部代码直接访问类的私有数据和私有方法,从而提高代码的安全性。
4)降低代码的耦合度。类的界面和实现分离,可以使类的实现部分与其他代码解耦,从而降低代码的耦合度,提高代码的可维护性和可扩展性。

在终端里可以使用下面指令执行:将MyClass.cpp文件编译成目标文件,并将其与main.cpp文件一起链接成可执行文件,才能正确运行程序。

g++ -c MyClass.cpp -o MyClass.o 
g++ main.cpp MyClass.o -o main
./main.exe

当然这个算比较简单的了,复杂一些需要上Cmake

1.3、构造函数,析构函数,拷贝构造函数

构造函数和析构函数是 C++ 中特殊的成员函数,它们分别在对象构造和析构时被调用。
构造函数的主要作用是初始化对象的成员变量,为对象提供一个合理的初始状态。当我们创建一个对象时,编译器会自动调用对象的构造函数。如果我们没有定义构造函数,编译器会生成一个默认构造函数,它不做任何事情。但如果我们需要在对象创建时进行一些初始化操作,就需要定义自己的构造函数。
析构函数的主要作用是在对象销毁时释放资源,例如关闭文件、释放内存等。当对象被销毁时,编译器会自动调用对象的析构函数。如果我们没有定义析构函数,编译器会生成一个默认析构函数,它不做任何事情。但如果我们需要在对象销毁时进行一些清理操作,就需要定义自己的析构函数。
总之,构造函数和析构函数是 C++ 中非常重要的特殊成员函数,它们分别在对象构造和析构时被调用,用于初始化对象的成员变量和释放对象占用的资源。

例1.1加入构造函数和析构函数,得到例1.2,可以感受一下构造函数和析构函数的作用:

#include <iostream>
using namespace std;

class MyClass {
public:
    MyClass(int data) : privateData(data) {
        protectedData = data * 2;//初始化变量
        cout << "MyClass constructor called." << endl;
    }

    ~MyClass() {
        cout << "MyClass destructor called." << endl;
    }

    void setData(int shuru) {
        privateData = shuru;
        protectedData = shuru * 2;
        cout << "setData: privateData = " << privateData << ", protectedData = " << protectedData << endl;
        privateFunc();
        protectedFunc();
    }

    int getData() {
        return privateData;
    }

protected:
    int protectedData;
    void protectedFunc() {
        cout << "This is a protected function." << endl;
    }

private:
    int privateData;
    void privateFunc() {
        cout << "This is a private function." << endl;
    }
};

int main() {
    MyClass obj(100);
    obj.setData(12345);
    cout << "Data: " << obj.getData() << endl;

    return 0;
}

这是一个构造函数的初始化列表,用于初始化私有成员变量privateData。privateData(data)表示将传入的参数data赋值给私有成员变量privateData。这种方式比在构造函数的函数体中直接赋值更高效,因为它避免了在构造函数体中再次对成员变量进行初始化。

当然一个类中,构造函数的形态不止一种,下面是一个例子:

#include <iostream>
using namespace std;

class MyClass {
public:
    MyClass() : privateData(0), protectedData(0) {
        cout << "MyClass default constructor called." << endl;
    }

    MyClass(int data) : privateData(data) {
        protectedData = data * 2;
        cout << "MyClass constructor with one parameter called." << endl;
    }

    MyClass(int data1, int data2) : privateData(data1), protectedData(data2) {
        cout << "MyClass constructor with two parameters called." << endl;
    }

    ~MyClass() {
        cout << "MyClass destructor called." << endl;
    }

    void setData(int shuru) {
        privateData = shuru;
        protectedData = shuru * 2;
        cout << "setData: privateData = " << privateData << ", protectedData = " << protectedData << endl;
        privateFunc();
        protectedFunc();
    }

    int getData() {
        return privateData;
    }

protected:
    int protectedData;
    void protectedFunc() {
        cout << "This is a protected function." << endl;
    }

private:
    int privateData;
    void privateFunc() {
        cout << "This is a private function." << endl;
    }
};

int main() {
    MyClass obj1;
    MyClass obj2(100);
    MyClass obj3(100, 200);
    obj2.setData(12345);
    cout << "Data: " << obj2.getData() << endl;

    return 0;
}

这个代码中,我们添加了一个默认构造函数MyClass(),一个带有一个参数的构造函数MyClass(int data),和一个带有两个参数的构造函数MyClass(int data1, int data2)。同时,我们也修改了构造函数的输出信息,以便更好地区分它们。
输出结果:
在这里插入图片描述

构造函数和析构函数的关系:

构造函数和析构函数是成对出现的,构造函数用于初始化对象,而析构函数用于清理对象。在对象创建时,构造函数会被调用一次,而在对象销毁时,析构函数会被调用一次。因此,它们是一一对应的。
在程序中,构造函数和析构函数的调用次数取决于对象的创建和销毁。如果只创建了一个对象,那么构造函数和析构函数各被调用一次。如果创建了多个对象,那么每个对象都会调用一次构造函数和析构函数。如果对象是在栈上创建的,那么它们的构造函数和析构函数会在进入和离开作用域时被调用。如果对象是在堆上创建的,那么需要手动调用delete来销毁对象,这时析构函数会被调用。
需要注意的是,如果一个类继承了另一个类,那么在创建和销毁对象时,构造函数和析构函数的调用顺序是从基类到派生类的。也就是说,先调用基类的构造函数,再调用派生类的构造函数;先调用派生类的析构函数,再调用基类的析构函数。

除此之外,还有一种特殊的构造函数:拷贝构造函数
拷贝构造函数是一种特殊的构造函数,用于将一个对象的值复制到另一个对象中。拷贝构造函数的作用是创建一个新对象,并将已有对象的值复制到新对象中。它常用于以下三种情况:
1)用一个已有对象来初始化一个新对象。
2)将一个对象作为参数传递给一个函数。
3)在函数中返回一个对象。
举个例子:

#include <iostream>
using namespace std;

class MyClass {
public:
    MyClass() : privateData(0), protectedData(0) {
        cout << "MyClass default constructor called." << endl;
    }

    MyClass(int data) : privateData(data) {
        protectedData = data * 2;
        cout << "MyClass constructor with one parameter called." << endl;
    }

    MyClass(int data1, int data2) : privateData(data1), protectedData(data2) {
        cout << "MyClass constructor with two parameters called." << endl;
    }

    MyClass(const MyClass& other) {
        privateData = other.privateData;
        protectedData = other.protectedData;
        cout << "MyClass copy constructor called." << endl;
    }

    ~MyClass() {
        cout << "MyClass destructor called." << endl;
    }

    void setData(int shuru) {
        privateData = shuru;
        protectedData = shuru * 2;
        cout << "setData: privateData = " << privateData << ", protectedData = " << protectedData << endl;
        privateFunc();
        protectedFunc();
    }
       int getData() {
        return privateData;
    }

protected:
    int protectedData;
    void protectedFunc() {
        cout << "This is a protected function." << endl;
    }

private:
    int privateData;
    void privateFunc() {
        cout << "This is a private function." << endl;
    }
};

void func1(MyClass obj) {
    cout << "func1 called." << endl;
}

MyClass func2() {
    cout << "func2 called." << endl;
    MyClass obj(456);
    return obj;
}

int main() {
    MyClass obj1;
    MyClass obj2(100);
    MyClass obj3(100, 200);
    obj2.setData(12345);
    cout << "Data: " << obj2.getData() << endl;

    MyClass obj4(obj2);
    MyClass obj5 = obj3;

    func1(obj4);
    MyClass obj6 = func2();

    return 0;
}

这里添加了一个拷贝构造函数,用于将一个对象的值复制到另一个对象中。同时,我添加了两个函数,一个是将对象作为参数传递给函数,另一个是在函数中返回对象。这两个函数都会自动调用拷贝构造函数。
在 main 函数中,我创建了几个对象,并调用了它们的成员函数。然后,我创建了两个新的对象,一个是通过拷贝构造函数创建的,另一个是通过赋值运算符创建的。最后,我调用了两个函数,一个是将对象作为参数传递给函数,另一个是在函数中返回对象。在这两个函数中,都会自动调用拷贝构造函数。

在这里插入图片描述

在这些情况下,如果没有定义拷贝构造函数,编译器会自动生成一个默认的拷贝构造函数来完成对象的复制。如果需要进行深拷贝,需要自己定义拷贝构造函数。

1.4、静态数据成员和静态成员函数

静态数据成员是指属于类的成员,而不是属于类的对象的成员。它们是在类被定义时被声明的,而不是在类的对象被创建时被定义的。它们被所有该类的对象所共享,因此它们的值在所有对象之间都是相同的。静态数据成员在程序开始时候被创建,在程序结束时被销毁(而不是构造和析构)

静态数据成员的存在有以下几个好处:
与普通成员变量不同,静态数据成员不需要在每个对象中都存储一份。这可以节省内存空间。
静态数据成员可以被所有该类的对象所共享,这使得它们可以用于在类的所有对象之间传递信息。
静态数据成员可以在类的外部被访问,这使得它们可以用于实现类似于全局变量的功能。
静态数据成员可以被用作常量表达式,这使得它们可以用于在编译时计算常量值。

静态成员函数是指在类中使用 static 关键字修饰的成员函数。静态成员函数不依赖于任何对象,可以直接通过类名调用,而不需要创建对象。因此,静态成员函数不能访问非静态成员变量和非静态成员函数,只能访问静态成员变量和静态成员函数。

(示例):

#include <iostream>
using namespace std;

class MyClass {
public:
    MyClass() : privateData(0), protectedData(0) {
        cout << "MyClass default constructor called." << endl;
        count++; // 每次创建对象时,对象数量加1
    }

    MyClass(int data) : privateData(data) {
        protectedData = data * 2;
        cout << "MyClass constructor with one parameter called." << endl;
        count++; // 每次创建对象时,对象数量加1
    }

    MyClass(int data1, int data2) : privateData(data1), protectedData(data2) {
        cout << "MyClass constructor with two parameters called." << endl;
        count++; // 每次创建对象时,对象数量加1
    }

    MyClass(const MyClass& other) {
        privateData = other.privateData;
        protectedData = other.protectedData;
        cout << "MyClass copy constructor called." << endl;
        count++; // 每次创建对象时,对象数量加1
    }

    ~MyClass() {
        cout << "MyClass destructor called." << endl;
        count--; // 每次销毁对象时,对象数量减1
    }

    void setData(int shuru) {
        privateData = shuru;
        protectedData = shuru * 2;
        cout << "setData: privateData = " << privateData << ", protectedData = " << protectedData << endl;
        privateFunc();
        protectedFunc();
    }
    
    int getData() {
        return privateData;
    }

    static int getCount() {
        return count; // 返回对象数量
    }

protected:
    int protectedData;
    void protectedFunc() {
        cout << "This is a protected function." << endl;
    }

private:
    int privateData;
    void privateFunc() {
        cout << "This is a private function." << endl;
    }

    static int count; // 所有对象的数量
};

int MyClass::count = 0; // 在类外部初始化静态数据成员

void func1(MyClass obj) {
    cout << "func1 called." << endl;
}

MyClass func2() {
    cout << "func2 called." << endl;
    MyClass obj(456);
    return obj;
}

int main() {
    MyClass obj1;
    MyClass obj2(100);
    MyClass obj3(100, 200);
    obj2.setData(12345);
    cout << "Data: " << obj2.getData() << endl;

    MyClass obj4(obj2);
    MyClass obj5 = obj3;

    cout << "Total objects: " << MyClass::getCount() << endl; // 输出对象数量

    func1(obj4);
    MyClass obj6 = func2();

    cout << "Total objects: " << MyClass::getCount() << endl; // 输出对象数量

    return 0;
}

静态成员经常用来做计数器的功能,就像上面代码所示。
当然静态数据成员可以被对象引用,比如MyClass::getCount()其实和obj6.getCount()实现的效果差不多,但是:
MyClass::getCount() 是静态调用,不需要创建对象,可以在任何地方调用;

obj6.getCount() 是动态调用,需要先创建对象,然后通过对象名调用。

另外需要注意的是,静态成员函数只能访问静态成员变量和静态成员函数,而不能访问非静态成员变量和非静态成员函数。因此,如果需要访问非静态成员变量或非静态成员函数,就需要通过对象名调用成员函数。

1.5、友元函数,友元类

友元是C++语言中的一个特殊概念,它允许某个函数或类访问另一个类的保护成员和私有成员。C++中的封装性要求类的私有成员和保护成员只能被类的成员函数访问,而友元机制则打破了这个限制,允许某些外部函数或类访问私有成员和保护成员,从而提高了程序的灵活性和可扩展性。

友元函数可以放在类中的任意位置,实现部分放在类外。

友元类是指一个类可以访问另一个类的私有成员和保护成员,这个类就是另一个类的友元类。友元类的声明方式和友元函数类似,需要在类的声明中使用friend关键字进行声明。
友元类可以访问被它所声明的类的私有成员和保护成员,但是它本身并不是被它所声明的类的成员,因此它不能直接访问被它所声明的类的成员变量和成员函数。如果需要访问被它所声明的类的成员变量和成员函数,可以通过类对象或者指针来访问。

下面是一个例子:

#include <iostream>
using namespace std;

class MyClass {
public:
    MyClass() : privateData(0), protectedData(0) {
        cout << "MyClass default constructor called." << endl;
        count++; // 每次创建对象时,对象数量加1
    }

    MyClass(int data) : privateData(data) {
        protectedData = data * 2;
        cout << "MyClass constructor with one parameter called." << endl;
        count++; // 每次创建对象时,对象数量加1
    }

    MyClass(int data1, int data2) : privateData(data1), protectedData(data2) {
        cout << "MyClass constructor with two parameters called." << endl;
        count++; // 每次创建对象时,对象数量加1
    }

    MyClass(const MyClass& other) {
        privateData = other.privateData;
        protectedData = other.protectedData;
        cout << "MyClass copy constructor called." << endl;
        count++; // 每次创建对象时,对象数量加1
    }

    ~MyClass() {
        cout << "MyClass destructor called." << endl;
        count--; // 每次销毁对象时,对象数量减1
    }

    void setData(int shuru) {
        privateData = shuru;
        protectedData = shuru * 2;
        cout << "setData: privateData = " << privateData << ", protectedData = " << protectedData << endl;
        privateFunc();
        protectedFunc();
    }
    
    int getData() {
        return privateData;
    }

    static int getCount() {
        return count; // 返回对象数量
    }

protected:
    int protectedData;
    void protectedFunc() {
        cout << "This is a protected function." << endl;
    }

private:
    int privateData;
    void privateFunc() {
        cout << "This is a private function." << endl;
    }

    static int count; // 所有对象的数量

    friend void friendFunc(MyClass obj); // 声明友元函数
    friend class FriendClass; // 声明友元类,FriendClass是Myclass的友元类
};

int MyClass::count = 0; // 在类外部初始化静态数据成员

void friendFunc(MyClass obj) { // 定义友元函数
    cout << "friendFunc called, privateData = " << obj.privateData << endl;
    obj.privateFunc();
}

class FriendClass { // 定义友元类
public:
    void friendClassFunc(MyClass obj) {
        cout << "FriendClass called, protectedData = " << obj.protectedData << endl;
        obj.protectedFunc();
    }
};

void func1(MyClass obj) {
    cout << "func1 called." << endl;
    friendFunc(obj); // 调用友元函数
}
MyClass func2() {
    cout << "func2 called." << endl;
    MyClass obj(456);
    return obj;
}
int main() {
    MyClass obj1;
    MyClass obj2(100);
    MyClass obj3(100, 200);
    obj2.setData(12345);
    cout << "Data: " << obj2.getData() << endl;
    MyClass obj4(obj2);
    MyClass obj5 = obj3;

    cout << "Total objects: " << MyClass::getCount() << endl; // 输出对象数量

    func1(obj4);

    FriendClass friendObj; // 创建友元类对象
    friendObj.friendClassFunc(obj2); // 调用友元类的成员函数

    MyClass obj6 = func2();

    cout << "Total objects: " << MyClass::getCount() << endl; // 输出对象数量

    return 0;

}

友元的弊端主要有以下几点:
破坏了封装性:友元可以访问类的私有成员和保护成员,这破坏了封装性,可能会导致类的安全性降低。

可能会导致耦合度增加:友元函数或友元类需要知道类的实现细节,这可能会导致类和友元之间的耦合度增加,使得类的实现变得更加复杂。

友元不具有继承性:如果一个类是另一个类的友元,那么它并不具有继承性,即它不能访问派生类的私有成员和保护成员。
因此,在使用友元时需要慎重考虑,只有在必要的情况下才应该使用友元。

二、类的实现——对象

2.1、对象的静态分配,动态分配(堆对象)

对象内存的静态分配和动态分配是指在程序运行时,对象所占用的内存空间是在编译时确定还是在运行时动态分配的。
静态分配是指在编译时为对象分配固定大小的内存空间,这种方式也称为栈分配。栈是一种先进后出的数据结构,它的内存分配和释放是由系统自动完成的,程序员不需要手动管理内存。静态分配的优点是速度快,缺点是内存空间固定,不够灵活,无法动态扩展。
动态分配是指在程序运行时根据需要动态地分配内存空间,这种方式也称为堆分配。堆是一种动态分配内存的方式,程序员需要手动管理内存的分配和释放。动态分配的优点是灵活性强,可以动态地扩展内存空间,缺点是速度较慢,容易出现内存泄漏和内存碎片等问题。
对于对象的内存分配,一般情况下建议使用动态分配,尤其是对象的大小不确定或者需要动态扩展时。但是在某些情况下,静态分配也是一种不错的选择,例如对象的大小固定且较小,或者需要频繁创建和销毁对象时,使用静态分配可以提高程序的运行效率。

静态分配的对象也称为自动变量(automatic variable)、栈变量(stack variable)或局部变量(local variable)。它们的内存在程序编译时就已经分配好了,作用域只在当前代码块中,当代码块执行完毕时,它们会自动被销毁。
动态分配的对象也称为堆对象(heap object)、动态对象(dynamic object)或者动态内存分配对象(dynamically allocated object)。它们的内存空间在程序运行时动态分配,作用域可以跨越多个代码块,需要手动管理内存的分配和释放。

下面是堆对象建立删除,堆对象数组建立删除的例子

#include <iostream>
using namespace std;

class MyClass
{
public:
    MyClass() { cout << "MyClass constructed!" << endl; }
    ~MyClass() { cout << "MyClass destructed!" << endl; }
};

int main()
{
    // 建立堆对象
    MyClass* ptr = new MyClass();
    // 使用堆对象
    cout << "Using heap object..." << endl;
    // 删除堆对象
    delete ptr;
    return 0;
}
#include <iostream>
using namespace std;

class MyClass
{
public:
    MyClass() { cout << "MyClass constructed!" << endl; }
    ~MyClass() { cout << "MyClass destructed!" << endl; }
};

int main()
{
    // 建立堆对象数组
    MyClass* arr = new MyClass[5];
    // 使用堆对象数组
    cout << "Using heap object array..." << endl;
    // 删除堆对象数组
    delete[] arr;
    return 0;
}

2.2、子对象

2.3、this指针

this指针是一个指向当前对象的指针,它在成员函数中使用。this指针的作用是为了区分同名的成员变量和局部变量。在成员函数中,如果有一个参数与成员变量同名,那么在函数中直接使用该变量名时,编译器会默认使用参数而不是成员变量。这时可以使用this指针来明确指出要使用的是成员变量而不是参数。
另外,this指针还可以用于在一个成员函数中返回当前对象的引用。例如,可以在一个成员函数中返回*this,表示返回当前对象的引用。这在链式调用中非常常见,可以使代码更加简洁易读。

举个例子:

#include <iostream>
using namespace std;

class Person {
public:
    int age;
    int getAge() {
        return this->age;
    }
};

int main() {
    Person person1;
    person1.age = 18;
    cout << "person1's age is " << person1.getAge() << endl;

    Person person2;
    person2.age = 25;
    cout << "person2's age is " << person2.getAge() << endl;

    return 0;
}

上面等价于下面:

```cpp
#include <iostream>
using namespace std;

class Person {
public:
    int age;
    int getAge() {
        return age;
    }
};

int main() {
    Person person1;
    person1.age = 18;
    cout << "person1's age is " << person1.getAge() << endl;

    Person person2;
    person2.age = 25;
    cout << "person2's age is " << person2.getAge() << endl;

    return 0;
}

在成员函数中,可以直接访问类的成员变量,不需要使用"this"指针。因此,"return this->age"和"return age"是等价的。不过,使用"this"指针可以明确地表示当前对象,增加代码的可读性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/605782.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【SpringCloud——Elasticsearch(中)】

一、DSL查询语法以及整合JAVA代码使用 以下操作案例均基于上篇的hotel索引库及其数据进行。 1、查询基本语法 GET /indexName/_search {"query": {"查询类型":{"查询条件":"条件值"}} } 2、查询所有 2.1、DSL语句 #查询所有 GET …

Java并发编程面试题——线程池

目录 1.什么是线程池&#xff1f;有什么优缺点&#xff1f;2.创建线程池的方式有哪些&#xff1f;2.1.通过 Executor 框架的工具类 Executors 来创建不同类型的线程池2.2.使用 ThreadPoolExecutor 类自定义线程池2.3.注意事项 3.自定义线程池时有哪些参数&#xff1f;它们各有说…

笔试强训 Day 7

选择题&#xff1a; 1.在&#xff08;&#xff09;情况下适宜采用 inline 定义内联函数 A 函数体含有循环语句 B 函数体含有递归语句C 函数代码少、频繁调用 D 函数代码多&#xff0c;不常调用 复习一下内联函数 在编译阶段&#xff0c;会将内联函数展开 —— 将函数调用替换成…

四、若依(前后端分离)项目构建docker 镜像

若依(前后端分离&#xff09;项目构建docker 镜像 1. 构建好ruoyi-admin.jar包&#xff0c;上传到服务器项目目录下 2. 创建conf目录将若依项目&#xff08;Spring boot &#xff09;配置文件修改好&#xff0c;上传存入conf目录 注意&#xff1a;这里的地址不能写127.0.0.1和…

ur5在gazebo中仿真的官方源码浅析

一 复现 好久之前初学rosgazebo机械臂仿真的时候总有些懵&#xff0c;用的是ur5机械臂&#xff0c;现在回过头来看好像看懂了一些&#xff0c;故重新理清了一下功能包的逻辑&#xff0c;方便查阅。 官方源码 本文参考 ubuntu16.04安装UR3/UR5/UR10机械臂的ROS驱动并实现gazebo…

chatgpt赋能python:Python列表从后往前遍历

Python列表从后往前遍历 作为一门广泛应用于数据科学、机器学习和Web开发的高级编程语言&#xff0c;Python为开发人员和科学家们提供了很多便利。在Python里面&#xff0c;列表是一种非常常见的数据结构&#xff0c;它允许开发人员存储和处理多个元素。但是&#xff0c;有时候…

5款提高工作效率的无广告软件

今天推荐一些可以大幅度提升办公效率的小软件&#xff0c;安全无毒&#xff0c;下载简单&#xff0c;最重要的是没有广告&#xff01; 1.照片处理——Darktable Darktable是一款用于处理和管理数码照片的工具。它可以让你对RAW格式的照片进行非破坏性的编辑,并提供多种模块和…

Nginx 启动成功无法访问网页

查看是否有Nginx进程 ps -ef | grep nginx 如下图有三个进程就是启动成功了 端口 因为Nginx我配置的是80端口&#xff0c;所以只要检查80端口是否开放即可 netstat -lnt | grep 80tcp: 这表示所显示的连接是基于TCP协议的。0.0.0.0:80: 这是本地监听的IP地址和端口号。在这…

Zabbix5通过脚本自定义Nginx监控

1、客户端配置 1.1、nginx开启nginx status 使用 zabbix 监控 nginx&#xff0c;首先 nginx 需要配置 ngx_status&#xff0c;nginx.conf加入以下配置&#xff0c;并重启Nginx或reload location /ngx_status { stub_status on; access_log off; #allow 127.0.0.1; #deny all…

C语言---初识结构体

1、结构体的声明 1.1、结构的基础知识 结构是一些值得集合&#xff0c;这些值称为成员变量。结构的每一个成员可以是不同类型的变量。 char、short、int、long、long、float、double是内置类型。 比如说&#xff0c;我们想要描述单一的成绩&#xff0c;身高我们直接用int类型就…

FPGA时序约束--基础理论篇

FPGA开发过程中&#xff0c;离不开时序约束&#xff0c;那么时序约束是什么&#xff1f;简单点说&#xff0c;FPGA芯片中的逻辑电路&#xff0c;从输入到输出所需要的时间&#xff0c;这个时间必须在设定的时钟周期内完成&#xff0c;更详细一点&#xff0c;即需要满足建立和保…

MokaPeople 上线 300 天:主打管理者视角和全员体验

当前&#xff0c;我们是身处的时代已从 VUCA 向 BANI 转变&#xff0c;在政策、经济和技术等多方面因素的驱动下&#xff0c;数字化转型已成为企业发展的必然趋势。 尤其在当下对于人才环境中的竞争态势也不得不迫使 HR 转型也进入了关键性的时刻。 6 月 2 日&#xff0c;国内…

TCP协议的相关特性

目录 TCP特点概要 TCP协议段格式 TCP原理 确认应答 超时重传 连接管理(三次握手,四次挥手) 三次握手 四次挥手 流水线传输 滑动窗口 滑动窗口ACK丢失 滑动窗口数据报丢失 流量控制 拥塞控制 延迟应答 停止等待协议 回退N帧协议 面向字节流 缓冲区 粘包问题 TCP异常 &…

手撕源码(三)ArrayList(JDK8)

目录 1.使用示例2.new ArrayList<>() 解析2.1 空列表2.2 默认大小的共享数组实例2.3 构造方法 3.new ArrayList<>(initialCapacity) 解析3.1 指定大小的共享数组实例3.2 构造方法 4.add() 解析4.1 容量大小4.2 add() 解析4.3 ensureCapacityInternal() 解析1&#…

【吴恩达GANs】【C1W4】Conditional Controllabel Generation

视频链接&#xff1a;吴恩达DeepLearning.ai之生成对抗网络&#xff08;GANS&#xff09;专业化〔Andrew Ng〕 4-2 Conditional generation intuition Unconditional Generation&#xff1a;从随机类中得到输出&#xff0c;每次输出的类也都是随机的&#xff0c;无法得到指定…

Redis和Mysql数据同步方案---延迟双删

一般场景下数据库和redis的同步机制&#xff1a; 针对有请求来读取数据库的场景&#xff1a; 但是如果有想要修改数据库内容的场景该怎么保持同步呢&#xff1f; 在我们访问redis时&#xff0c;redis中的数据可能不是热点数据&#xff0c;即此时数据库的更新操作已经完成&…

chatgpt赋能python:Python几行代码:打造高效SEO工具

Python几行代码&#xff1a;打造高效SEO工具 Python作为一种易用、可靠的编程语言&#xff0c;在数据处理、网页爬取等方面都有广泛应用。而对于SEO工作者来说&#xff0c;利用Python写几行简单的代码&#xff0c;可以帮助我们更高效地分析网站数据、监控关键词排名、抓取竞争…

测试工程师:“ 这锅我不背 ” ,如何回怼开发....?

前言 在一个周末的早餐我被同事小周叫出去跑步&#xff0c;本想睡个懒觉&#xff0c;但是看他情绪不太稳定的样子&#xff0c;无奈艰难爬起陪他去跑步。 只见她气冲冲的对着河边大喊&#xff1a;真是冤枉啊&#xff01;!&#xff01; 原来是在工作中被莫名其妙背锅&#xff0…

计算机存储体系

目录 一、基本概念 二、主存储器的基本组成 三、SRAM和DRAM 四、只读存储器ROM 五、主存储器与CPU的连接 六、双端口RAM和多模块存储器 七、磁盘存储器 八、固态硬盘SSD 九、Cache高速缓冲存储器 十、虚拟存储系统 一、基本概念 存储器的层次结构 主存——辅存&…

1_5 光流法计算VO(optical_flow)

采用特征点法做VO存在耗时较大的问题&#xff0c;一般耗时情况&#xff1a;如下 (1) 在图像中提取特征点并计算特征描述&#xff0c; 非常耗时 ~10ms ORB&#xff0c;shift耗时更多&#xff1b; (2) 在不同图像中寻找特征匹配&#xff0c; 非常耗时 …