C++进阶语法——OOP(面向对象)【学习笔记(四)】

news2024/11/14 19:12:25

文章目录

      • 1、C++ OOP⾯向对象开发
        • 1.1 类(classes)和对象(objects)
        • 1.2 public、private、protected访问权限
        • 1.3 实现成员⽅法
        • 1.4 构造函数(constructor)和 析构函数(destructor)
          • 1.4.1 构造函数(constructor)
          • 1.4.2 析构函数(destructor)
        • 1.5 代理构造函数(delegating constructor)
        • 1.6 拷⻉构造函数(copy constructor)
        • 1.7 浅拷贝(shallow copy)和深拷贝(deep copy)
          • 1.7.1 浅拷⻉(shallow copy)
          • 1.7.2 深拷⻉(deep copy)
        • 1.8 在类中使⽤const
        • 1.9 在类中使⽤static
        • 1.10、 struct 和 class区别

1、C++ OOP⾯向对象开发

1.1 类(classes)和对象(objects)

简单介绍一下类:

• C++ 类(classes)
------->• 创建对象⽤的蓝图(blueprint)
------->• ⽤户⾃定义的数据类型
------->• 有成员属性(data)和成员⽅法(methods)
------->• 可以隐藏属性和⽅法(private)
------->• 可以提供公共接⼝(public)
示例: Account, Student, std::vector, std::string

简单介绍一下对象:

• C++ 对象(objects)
------->• 由类创建⽽来
------->• 表示类的⼀个具体的实例(Instance)
------->• 可以有很多个实例,每个都有独⽴的身份
------->• 每个对象都可以使⽤类中定义的⽅法
• Account对象示例:
------->• Jobs、Alice 的account是Account类的实例
------->• 每个实例都有它的余额、可以提现、存钱

虽然 int 不是类,这里把它看成一个类,int 后面的 high_score 和 low_score 可以看成 int 类实例化后的对象;
创建 Account 类后,实例化2个对象,分别是:jobs_account 和 alice_account;
std是类,后面跟着的容器 vector 和字符串 string 是对象;
如下图所示,

在这里插入图片描述

A、声明一个类:

在这里插入图片描述

B、创建类的对象:

还可以根据类创建一个指针,并且在堆上使用关键字 new 动态分配内存空间,使用后用 delete 删除释放内存空间,

在这里插入图片描述

一旦有了类的对象,就可以像 C++ 其他变量去使用

在这里插入图片描述

代码:

#include <iostream>
#include <string>
#include <vector>

using namespace std;

class Account
{
    // 属性
    string name {"None"};
    double balance {0.0};

    // 方法
    bool deposit(double amount); // 存款
    bool withdraw(double amount); // 取款
};

int main()
{
    Account jobs_account;  // 初始化属性
    Account alice_account;  // 初始化属性

    Account accounts [] {jobs_account, alice_account}; // 数组

    vector<Account> accounts_vec {jobs_account}; // vector
    accounts_vec.push_back(alice_account);

    Account *p_account = new Account(); // 指针
    delete p_account;

    return 0;
}

C、获取类的属性或⽅法:

使⽤点操作符:

在这里插入图片描述

如果是⼀个指向对象的指针,可以解引⽤或者使⽤箭头操作符,
需要注意: 使用 . 操作符的时候需要在前面加一个括号 () ,因为 . 操作符的优先级高于 * 解引用运算符的优先级,

在这里插入图片描述

代码:

#include <iostream>
#include <string>
#include <vector>

using namespace std;

class Account
{
public:    
    // 属性
    string name {"None"};
    double balance {0.0};

    // 方法
    bool deposit(double amount){
        balance += amount;
        cout << name << "刚存入" << amount << "元,现在余额为" << balance << "元" << endl;
        return true;
    }; // 存款
    bool withdraw(double amount){
        if (balance >= amount){
            balance -= amount;
            cout << name << "刚取出" << amount << "元,现在余额为" << balance << "元" << endl;
            return true;
        } else {
            cout << name << "余额不足,取款失败" << endl;
            return false;
        }
    }; // 取款
};

int main()
{
    Account jobs_account;
    jobs_account.name = "Jobs";
    jobs_account.balance = 1000.0;

    jobs_account.deposit(500.0);

    Account *alice_account = new Account();
    (*alice_account).name = "Alice";
    alice_account->balance = 2000.0;

    (*alice_account).deposit(1000.0);
    alice_account->withdraw(500.0);

    return 0;
}
1.2 public、private、protected访问权限

• public
----->• 可以被任何实体访问
• private
----->• 只能被本类的⽅法访问
• protected
----->• 可以被本类和⼦类(继承)的⽅法访问

在这里插入图片描述

在这里插入图片描述

代码:

#include <iostream>
#include <string>
#include <vector>

using namespace std;

class Account
{
private:    
    // 属性
    string name {"None"};
    double balance {0.0};

public:
    // 方法
    bool deposit(double amount){
        balance += amount;
        cout << name << "刚存入" << amount << "元,现在余额为" << balance << "元" << endl;
        return true;
    }; // 存款
    bool withdraw(double amount){
        if (balance >= amount){
            balance -= amount;
            cout << name << "刚取出" << amount << "元,现在余额为" << balance << "元" << endl;
            return true;
        } else {
            cout << name << "余额不足,取款失败" << endl;
            return false;
        }
    }; // 取款
};

int main()
{
    Account jobs_account;
    // jobs_account.name = "Jobs";
    // jobs_account.balance = 1000.0;

    // cout << jobs_account.name << "的余额为" << jobs_account.balance << "元" << endl;

    jobs_account.deposit(500.0);

    return 0;
}
1.3 实现成员⽅法

在类中定义成员方法,适用于代码量较少的程序,

在这里插入图片描述

在类外面定义成员方法,适用于代码量较大的程序,

在这里插入图片描述

代码:

编译器无法区分 set_name 函数是类内的函数还是其他函数,所以在 set_name 前面添加类名::,表示这是类的成员函数

#include <iostream>
#include <string>
#include <vector>

using namespace std;

class Account
{
private:
    // 属性
    string name {"None"};
    double balance {0.0};

public:
    // 方法

    // 设置余额
    void set_balance(double amount){balance = amount;};
    // 获取余额
    double get_balance(){return balance;};

    // 设置名称
    void set_name(string name);
    // 获取名称
    string get_name();

    // 存款
    bool deposit(double amount);
    // 取款
    bool withdraw(double amount);
};

void Account::set_name(string name){
    this->name = name; // this指针指向当前对象
}
string Account::get_name(){
    return name;
}
bool Account::deposit(double amount){
    balance += amount;
    cout << name << "刚存入" << amount << "元,现在余额为" << balance << "元" << endl;
    return true;
}
bool Account::withdraw(double amount){
    if (balance >= amount){
        balance -= amount;
        cout << name << "刚取出" << amount << "元,现在余额为" << balance << "元" << endl;
        return true;
    } else {
        cout << name << "余额不足,取款失败" << endl;
        return false;
    }
}



int main()
{
    Account alice_account;
    alice_account.set_name("Alice's account"); // 设置名称
    alice_account.set_balance(1000.0); // 设置余额

    cout << alice_account.get_name() << "的余额为" << alice_account.get_balance() << "元" << endl;

    alice_account.deposit(200.0);
    alice_account.withdraw(500.0);
    alice_account.withdraw(1500.0);

    return 0;
}

上面的代码看着比较繁杂,我们可以用头文件和源文件编写。
为了防止头文件被多次导入造成一些冲突,一般添加如下语句,关于头文件被多次导入造成一些冲突可参考这个链接:CSDN链接,例如创建 Account.h 头文件:

#ifndef ACCOUNT_H
#define ACCOUNT_H
#endif // ACCOUNT_H

整个 Account.h 头文件代码如下,一般不在头文件写 using namespace std;,一般显示地使用 std:string

#ifndef ACCOUNT_H
#define ACCOUNT_H
#include <string>

class Account
{
private:
    // 属性
    std::string name {"None"};
    double balance {0.0};

public:
    // 方法

    // 设置余额
    void set_balance(double amount){balance = amount;};
    // 获取余额
    double get_balance(){return balance;};

    // 设置名称
    void set_name(std::string name);
    // 获取名称
    std::string get_name();

    // 存款
    bool deposit(double amount);
    // 取款
    bool withdraw(double amount);
};

#endif // ACCOUNT_H

然后再根据头文件编写类的成员方法的定义,因为在源文件引入了头文件#include "Account.h",所以不需要再写 #include <string>,这里也是显示地引入 std::coutstd::endl

#include "Account.h"
#include <iostream>

void Account::set_name(std::string name){
    this->name = name; // this指针指向当前对象
}
std::string Account::get_name(){
    return name;
}
bool Account::deposit(double amount){
    balance += amount;
    std::cout << name << "刚存入" << amount << "元,现在余额为" << balance << "元" << std::endl;
    return true;
}
bool Account::withdraw(double amount){
    if (balance >= amount){
        balance -= amount;
        std::cout << name << "刚取出" << amount << "元,现在余额为" << balance << "元" << std::endl;
        return true;
    } else {
        std::cout << name << "余额不足,取款失败" << std::endl;
        return false;
    }
}

最后是程序的 main.cpp 文件,直接编译 main.cpp 即可,

#include <iostream>
#include <string>
#include <vector>
#include "Account.h" // 引入头文件

using namespace std;


int main()
{
    Account alice_account;
    alice_account.set_name("Alice's account"); // 设置名称
    alice_account.set_balance(1000.0); // 设置余额

    cout << alice_account.get_name() << "的余额为" << alice_account.get_balance() << "元" << endl;

    alice_account.deposit(200.0);
    alice_account.withdraw(500.0);
    alice_account.withdraw(1500.0);

    return 0;
}
1.4 构造函数(constructor)和 析构函数(destructor)
1.4.1 构造函数(constructor)

• 特殊的成员⽅法
对象创建的时候⾃动调⽤
• 适⽤于实例参数初始化
函数名和类的名称⼀致
• ⽆需设置返回类型
可以被重载(overload)

1.4.2 析构函数(destructor)

• 特殊的成员⽅法
• 函数名和类的名称⼀致,前⾯跟着⼀个~波浪符号
对象销毁的时候⾃动调⽤
• 没有参数,没有返回类型
• 只有⼀个析构函数(不能重载)
适⽤于释放内存等资源

如果不手动创建构造函数和析构函数,那么C++会自动帮助创建构造函数和析构函数,只不过都是空的,

构造函数(constructor)和析构函数(destructor):

在这里插入图片描述

构造函数在栈上创建,当程序运行结束时,他们各自的析构函数会被调用,所以会调用4次析构函数,

在这里插入图片描述

代码:

#include <iostream>
#include <string>
#include <vector>
using namespace std;

class Account
{
private:
    // 属性
    std::string name {"account"};
    double balance {0.0};
public:
    void setName(string name){ this->name = name; }; // 设置名称
    // 构造函数
    Account(){
        cout << "没有参数的构造函数被调用" << endl;
    };
    Account(std::string name){
        cout << "带string name参数的构造函数被调用" << endl;
    };
    Account(double balance){ 
        cout << "带double balance参数的构造函数被调用" << endl;
    };
    Account(string name, double balance){ 
        cout << "带string name和double balance参数的构造函数被调用" << endl;
    };
    // 析构函数
    ~Account(){ 
        cout << name << " 的析构函数被调用" << endl;
    };
};


int main()
{
    // 用{}表示作用域,{}内的程序运行后会调用析构函数
    {
        Account alice_account;
        alice_account.setName("Alice's account"); // 设置名称
    }
    // 出栈:后入先出
    {
        Account jobs_account;
        jobs_account.setName("Jobs's account"); 

        Account bill_account("Bill's account");
        bill_account.setName("Bill's account"); 

        Account steve_account(1000.0);
        steve_account.setName("Steve's account"); 
    }

    Account *mark_account = new Account("Mark's account", 1000.0);
    mark_account->setName("Mark's account");
    delete mark_account;

    return 0;
}

输出:

没有参数的构造函数被调用
Alice's account 的析构函数被调用
没有参数的构造函数被调用
带string name参数的构造函数被调用
带double balance参数的构造函数被调用
Steve's account 的析构函数被调用
Bill's account 的析构函数被调用
Jobs's account 的析构函数被调用
带string name和double balance参数的构造函数被调用
Mark's account 的析构函数被调用

构造函数初始化列表:

:name {name} 中,冒号后面的 name 类成员属性的 name,{} 里面的 name 是函数的形参 name,

在这里插入图片描述

代码1:

#include <iostream>
#include <string>
#include <vector>
using namespace std;

class Account
{
private:
    // 属性
    std::string name {"account"};
    double balance {0.0};
public:
    // 打印信息
    void printInfo();
    // 构造函数,初始化参数
    Account(string name, double balance);
   
};

void Account::printInfo(){
    cout << "name: " << name << ", balance: " << balance << endl;
}
// 构造函数内部初始化参数
Account::Account(string name, double balance){
    this->name = name;
    this->balance = balance;
}

int main()
{

    Account *mark_account = new Account("Mark's account", 1000.0);
    mark_account->printInfo(); // 打印信息
    delete mark_account;

    return 0;
}

输出:

name: Mark's account, balance: 1000

代码2:

#include <iostream>
#include <string>
#include <vector>
using namespace std;

class Account
{
private:
    // 属性
    std::string name {"account"};
    double balance {0.0};
public:
    // 打印信息
    void printInfo();
    // 构造函数,初始化参数
    Account();
    Account(string name);
    Account(string name, double balance);
   
};

void Account::printInfo(){
    cout << "name: " << name << ", balance: " << balance << endl;
}

// 构造函数内部初始化参数
// Account::Account(){
//     name = "None";
//     balance = 0.0;
// }
// Account ::Account(string name){
//     this->name = name;
//     balance = 0.0;
// }
// Account::Account(string name, double balance){
//     this->name = name;
//     this->balance = balance;
// }

// 构造函数初始化列表
Account::Account()
    :name{"none"}, balance{0.0}{
        
    }
Account::Account(string name)
    :name{name}, balance{0.0}{
        
    }

Account::Account(string name, double balance)
    :name{name}, balance{balance}{
        
    }

int main()
{
    Account alice_account;
    alice_account.printInfo(); // 打印信息

    Account jobs_account {"Jobs's account"};
    jobs_account.printInfo(); 

    Account bill_account {"Bill's account", 1000.0};
    bill_account.printInfo(); 

    return 0;
}

输出:

name: none, balance: 0
name: Jobs's account, balance: 0
name: Bill's account, balance: 1000
1.5 代理构造函数(delegating constructor)

• 重载的构造函数很相似
• 冗余的代码可能会导致错误
• C++ 允许使⽤代理构造函数
------>• 在⼀个构造函数初始化列表中调⽤另⼀个构造函数

代码: 建议使用 debug 查看程序运行过程

#include <iostream>
#include <string>
#include <vector>
using namespace std;

class Account
{
private:
    // 属性
    std::string name {"account"};
    double balance {0.0};
public:
    // 打印信息
    void printInfo();
    // 构造函数,初始化参数
    Account();
    Account(string name);
    Account(string name, double balance);
   
};

void Account::printInfo(){
    cout << "name: " << name << ", balance: " << balance << endl;
}

// 构造函数初始化列表
Account::Account()
    :Account {"none",0}{
        
    }
Account::Account(string name)
    :Account {name, 0}{
        
    }

Account::Account(string name, double balance)
    :name{name}, balance{balance}{
        
    }

int main()
{
    Account alice_account;
    alice_account.printInfo(); // 打印信息

    Account jobs_account {"Jobs's account"};
    jobs_account.printInfo(); 

    Account bill_account {"Bill's account", 1000.0};
    bill_account.printInfo(); 

    return 0;
}

输出:

name: none, balance: 0
name: Jobs's account, balance: 0
name: Bill's account, balance: 1000
1.6 拷⻉构造函数(copy constructor)

• 当对象被拷⻉时,C++必须从已存在的对象复制出⼀个新的对象
• 何时使⽤拷⻉构造函数?
------->• 以值传递⽅式传递对象给函数(作参数)
------->• 函数以值⽅式返回对象
------->• 使⽤已存在的对象复制新的对象
• 如果不提供⾃⼰写的copy constructor,编译器会⾃动⽣成⼀个(可能不符合要求),如果是指针,拷贝的是地址,所以编译器自动生成的拷贝构造函数是浅拷贝

A、拷⻉构造函数——值传递

在这里插入图片描述

B、拷⻉构造函数——以值⽅式返回

以值⽅式返回拷⻉构造函数返回的 an_account 副本

在这里插入图片描述

C、拷⻉构造函数——使⽤已存在的对象复制新的对象

在这里插入图片描述

D、拷⻉构造函数的声明

首先拷⻉构造函数也是构造函数,所以函数的名称和类的名称一样,函数的参数列表是使用引用的方式传递的,

在这里插入图片描述

在这里插入图片描述

代码:

#include <iostream>
#include <string>
#include <vector>
using namespace std;

class Account
{
private:
    // 属性
    string name {"account"};
    double balance {0.0};
public:
    string getName() {return name;} // 获取name
    double getBalance() {return balance;} // 获取balance
    // 构造函数
    Account(string name = "none", double balance = 0.0);
    // 析构函数
    ~Account();
    // 拷贝构造函数
    Account(const Account &source);
};

Account::Account(string name, double balance)
    :name {name}, balance {balance}
    {
        cout << "2个参数的构造函数被调用,name:" << name << endl;
    }

Account::~Account()
{
    cout << "析构函数被调用,name:" << name << endl;
}

// 拷贝构造函数:根据已存在对象的属性来更新新对象的属性(name,balance)
Account::Account(const Account &source)
    :name {source.name}, balance {source.balance} // 初始化列表
    {
        cout << "拷贝构造函数被调用,是" << source.name << "的拷贝" << endl;
    }
// 打印账户信息
void printAccountInfo(Account acc)
{
    cout << acc.getName() << "的余额是:" << acc.getBalance() << endl;
}
int main()
{
    // 1.值传递的方式给函数传递参数
    // Account alice_account;
    // printAccountInfo(alice_account);
    
    // 2.基于已存在的对象创建新的对象
    Account alice_account {"Alice's account", 1000.0};
    Account new_account {alice_account}; // 拷贝构造函数被调用
    return 0;
}

输出:

2个参数的构造函数被调用,name:Alice's account
拷贝构造函数被调用,是Alice's account的拷贝
析构函数被调用,name:Alice's account
析构函数被调用,name:Alice's account
1.7 浅拷贝(shallow copy)和深拷贝(deep copy)

• 如果不提供⾃⼰写的copy constructor,编译器会⽣成默认的
------>• 将⽬标对象的值逐个拷⻉过来;
------>• 如果是指针,拷⻉的是值(指向的地址),⽽不是指向的对象,称为浅拷贝
------>• 在析构函数中释放内存时,其他对象中的指针可能还在指向被释放的资源,在析构函数释放内存资源时可能会报错,例如下面的代码,如果使用编译器默认的拷贝构造函数,在进行析构函数释放内存资源时可能会报错

代码:

#include <iostream>
#include <string>
#include <vector>
using namespace std;

class Account
{
private:
    // 属性
    string name {"account"};
    double *balance {nullptr};
public:
    double get_balance() {return *balance;}; // 获取余额
    string get_name() {return name;}; // 获取名字

    // 构造函数
    Account(string name = "none", double balance = 0.0); // 有默认参数的构造函数
    // 拷贝构造函数
    Account(const Account &source);
    // 析构函数
    ~Account();

    
};
Account::Account(string name, double balance)
    {
        this->name = name;
        this->balance = new double {balance}; // 堆上分配内存
        cout << "2个参数的构造函数被调用,name: " << name << endl;
    }
// 拷贝构造函数    
Account::Account(const Account &source)
    :Account {source.name, *source.balance} // 代理构造函数
    {
        cout << "拷贝构造函数被调用,是" << source.name << "的拷贝" << endl;
    } 
    
Account::~Account(){
    if (balance != nullptr)
        delete balance; // 释放内存
    cout << "析构函数被调用,name: " << name << endl;
}

int main()
{
    // 演示浅拷贝和深拷贝
    Account alice_account {"Alice", 1000.0};
    Account new_account {alice_account}; // 拷贝构造函数被调用
    // cout << new_account.get_balance() << endl; // 1000.0
    return 0;
}

如果使用编译器默认的拷贝构造函数,在进行 alice_account 析构函数释放内存时会报错,如下图,如果使用自己写的拷贝构造函数就不会报错,

在这里插入图片描述

1.7.1 浅拷⻉(shallow copy)

如下图,alice_account 浅拷贝到 new_account,编译器会默认创建一个拷贝构造函数,它是逐个元素按值拷贝的如果是指针,则是拷贝的地址。当调用析构函数的时候,由于后进先出的原则,new_account 上的地址被释放后,alice_account 的地址也会被释放,但地址已经被释放,所以会造成堆空间重复释放的问题,导致程序报错,

在这里插入图片描述

编译器默认生成的拷贝构造函数如下:

在这里插入图片描述

1.7.2 深拷⻉(deep copy)

在函数内部,在堆上分配一个新的 double 类型的内存空间,初始化为1000,并且把新的内存空间给1000,

在这里插入图片描述

代码:

#include <iostream>
#include <string>
#include <vector>
using namespace std;

class Account
{
private:
    // 属性
    string name {"account"};
    double *balance {nullptr};
public:
    double get_balance() {return *balance;}; // 获取余额
    string get_name() {return name;}; // 获取名字

    // 构造函数
    Account(string name = "none", double balance = 0.0); // 有默认参数的构造函数
    // 拷贝构造函数
    Account(const Account &source);
    // 析构函数
    ~Account();

    
};
Account::Account(string name, double balance)
    {
        this->name = name;
        this->balance = new double {balance}; // 堆上分配内存
        cout << "2个参数的构造函数被调用,name: " << name << endl;
    }
// 拷贝构造函数    
Account::Account(const Account &source)
    :Account {source.name, *source.balance} // 代理构造函数
    {
        cout << "拷贝构造函数被调用,是" << source.name << "的拷贝" << endl;
    } 
    
Account::~Account(){
    if (balance != nullptr)
        delete balance; // 释放内存
    cout << "析构函数被调用,name: " << name << endl;
}

int main()
{
    // 演示浅拷贝和深拷贝
    Account alice_account {"Alice", 1000.0};
    Account new_account {alice_account}; // 拷贝构造函数被调用
    // cout << new_account.get_balance() << endl; // 1000.0
    return 0;
}
1.8 在类中使⽤const

• 常函数
------->• 函数名称后加const
------->• 函数体内不可以修改类成员属性
• 常对象
------->• 声明对象时前⾯加const
------->• 不可以修改常对象的成员属性
------->• 不能调用普通的成员方法,只能调⽤常函数

代码:

#include <iostream>
#include <string>
#include <vector>
using namespace std;


class Account
{
private:
    
    double balance {0.0};

public:
    string name {"account"};

    void set_new_name(string new_name) const{ // 修改名字
        // name = new_name;
    }
    string get_name() const{ // 获取名字
        return name;
    }
    // 构造函数
    Account(string name = "none", double balance = 0.0);
    ~Account();
};

Account::Account(string name, double balance)
    : balance{balance} ,name{name}{
        cout << "构造函数" << endl;
}

Account::~Account()
{
    cout << "析构函数" << endl;
}


int main()
{
    // 常函数
    // Account alice_account {"Alice", 1000.0};
    // alice_account.set_new_name("Alice2"); // 修改名字
    // cout << alice_account.get_name() << endl; // Alice2

    // 常对象
    const Account bob_account {"Bob", 2000.0};
    // bob_account.name = "Bob2"; // 修改名字
    cout << bob_account.get_name() << endl; // Bob2
    
    return 0;
}
1.9 在类中使⽤static

• 静态成员变量
------->• 所有对象共有同⼀份数据(数据共享)
------->• 在类中声明,类外初始化
• 静态成员函数
------->• 所有对象共享同⼀个函数
------->• 只能访问静态成员变量

在这里插入图片描述

代码:

#include <iostream>
#include <string>
#include <vector>
using namespace std;

class Account
{
private:
    // 属性
    string name {"account"};
    double balance {0.0};
    static int num_accounts;
public:
    static int get_num_accounts();
    Account(string name, double balance);
    ~Account();
};

int Account::num_accounts {0};

Account::Account(string name, double balance)
    :name{name}, balance{balance}{
        num_accounts++;
    }

Account::~Account()
{
    num_accounts--;
}

int Account::get_num_accounts() // 不需要使用static关键字
{
    // 静态成员方法只能访问静态成员变量
    // name = "test";
    return num_accounts;
}
int main()
{
    cout << Account::get_num_accounts() << endl;
    Account alice_account {"Alice's account", 1000.0};
    cout << alice_account.get_num_accounts() << endl;
    Account bob_account {"Bob's account", 2000.0};
    cout << Account::get_num_accounts() << endl;
    
    {
        Account test_account {"test", 100.0};
        cout << Account::get_num_accounts() << endl;
    }
    cout << Account::get_num_accounts() << endl;
    return 0;
}
1.10、 struct 和 class区别

区别在于 class 成员权限默认是 private,而 struct 的成员权限默认是 public,

在这里插入图片描述

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

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

相关文章

kubectl资源管理命令-陈述式

目录 一、陈述式对象管理 1、基本概念 2、基础命令使用 3、基本信息查看&#xff08;kubectl get&#xff09; 4、增删等操作 5、登录pod中的容器 6、扩容缩容pod控制器的pod 7、删除副本控制器 二、创建项目实例 1、创建 kubectl create命令 2、发布 kubectl …

Spring Cloud Gateway + Knife4j 4.3 实现微服务网关聚合接口文档

目录 前言Spring Cloud 整合 Knife4jpom.xmlapplication.ymlSwaggerConfig.java访问单服务接口文档 Spring Cloud Gateway 网关聚合pom.xmlapplication.yml访问网关聚合接口文档 接口测试**登录认证**获取登录用户信息 结语源码 前言 youlai-mall 开源微服务商城新版本基于 Sp…

怎样使用Mybatis数据库连接池?

怎样使用Mybatis数据库连接池&#xff1f; 首先是配置&#xff0c;如下图&#xff1a; 千万要注意&#xff0c;一个程序中只创建一个SqlSessionFactory对象&#xff0c;要不然每次执行sql都创新创建一个SqlSessionFactory对象的话&#xff0c;那么每次建立连接的时候都会先清…

Chimera:混合的 RLWE-FHE 方案

参考文献&#xff1a; [HS14] S. Halevi and V. Shoup. Algorithms in HElib. In Advances in Cryptology–CRYPTO 2014, pages 554–571. Springer, 2014.[HS15] S. Halevi and V. Shoup. Bootstrapping for HElib. In Advances in Cryptology–EUROCRYPT 2015, pages 641–6…

【Spring】快速入门Spring Web MVC

文章目录 1. 什么是Spring Web MVC1.1 MVC1.2 Spring MVC 2. 使用Spring MVC2.1 项目创建2.2 建立连接2.2.1 RequestMapping 注解2.2.2 RestController 注解2.2.3 RequestMapping 使⽤2.2.4 RequestMapping 是什么请求&#xff1f;POST&#xff1f;GET&#xff1f;…&#xff1…

Linux高性能服务器编程——ch8笔记

第8章 高性能服务器程序框架 8.1 服务器模型 服务器启动后&#xff0c;首先创建一个&#xff08;或多个&#xff09;监听socket&#xff0c;并调用bind函数将其绑定到服务器感兴趣的端口&#xff0c;然后调用listen函数等待客户连接。服务器稳定运行之后&#xff0c;客户端就可…

网盘限速问题解析:哪家网盘真的不限速?

天下苦网盘限速久矣。市面上一些网盘工具要不然是收费限流&#xff0c;要不然是需要额外购买下载券。哪家网盘真的不限速&#xff1f; Zoho Workdrive 企业网盘是真正的不限速网盘&#xff0c;上传和下载文件都不限速&#xff0c;真正做到用户的网速有多快&#xff0c;下载就有…

玩转ChatGPT:批量下载Alphafold的蛋白pdb文件

一、写在前面 突发奇想&#xff0c;想批量下载Alphafold网站的蛋白pdb文件&#xff0c;后续再做个分子对接用。又不想手动下载&#xff0c;来求助CSDN和GPT。 二、CSDN白嫖基础代码 CSDN大神多&#xff0c;这不&#xff0c;找到一个&#xff1a;Alphafold批量下载蛋白的pdb文…

Unity Shader当用户靠近的时候会出现吃鸡一样的光墙

效果图片 靠近墙壁 远离墙壁 材质球的设置 两张图片 使用方式 把这个脚本放到墙上&#xff0c;将player赋值给"_player"&#xff0c;然后运行&#xff0c;用户靠近就会根据距离显示光墙。 using UnityEngine;public class NewBehaviourScript : MonoBehaviour {pr…

【算法|贪心算法系列No.5】leetcode409. 最长回文串

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【手撕算法系列专栏】【LeetCode】 &#x1f354;本专栏旨在提高自己算法能力的同时&#xff0c;记录一下自己的学习过程&#xff0c;希望…

win10 + VS2017 编译libjpeg(jpeg-9b)

需要用到的文件&#xff1a; jpeg-9b.zip win32.mak 下载链接链接&#xff1a;https://pan.baidu.com/s/1Z0fwbi74-ZSMjSej-0dV2A 提取码&#xff1a;huhu 步骤1&#xff1a;下载并解压jpeg-9b。 这里把jpeg-9b解压到文件夹"D:\build-libs\jpeg\build\jpeg-9b" …

创纪录的1亿RPS DDoS攻击利用HTTP/2快速重置漏洞

导语&#xff1a;最近&#xff0c;一项创纪录的DDoS攻击引起了广泛关注。攻击者利用了HTTP/2协议中的一个快速重置漏洞&#xff0c;发起了一系列超大规模的攻击。本文将为大家详细介绍这次攻击的背景、影响以及应对措施。 攻击背景 最近&#xff0c;全球范围内遭受了一系列规模…

计算机操作系统重点概念整理-第六章 输入输出I/O管理【期末复习|考研复习】

第六章 输入输出I/O管理【期末复习|考研复习】 计算机操作系统系列文章传送门&#xff1a; 第一章 计算机系统概述 第二章 进程管理 第三章 进程同步 第四章 内存管理 第五章 文件管理 第六章 输出输出I/O管理 文章目录 第六章 输入输出I/O管理【期末复习|考研复习】前言六、输…

c++的4中类型转换操作符(static_cast,reinterpret_cast,dynamic_cast,const_cast),RTTI

目录 引入 介绍 static_cast 介绍 使用 reinterpret_cast 介绍 使用 const_cast 介绍 使用 dynamic_cast 介绍 使用 RTTI(运行时确定类型) 介绍 typeid运算符 dynamic_cast运算符 type_info类 引入 原本在c中,我们就已经接触到了很多类型转换 -- 隐式类型转…

论文阅读——GPT3

来自论文&#xff1a;Language Models are Few-Shot Learners Arxiv&#xff1a;https://arxiv.org/abs/2005.14165v2 记录下一些概念等。&#xff0c;没有太多细节。 预训练LM尽管任务无关&#xff0c;但是要达到好的效果仍然需要在特定数据集或任务上微调。因此需要消除这个…

YOLOv5配置文件之 - yaml

在YOLOv5的目录中&#xff0c;models文件夹里存储了YOLO的模型配置。 ./models/yolov5.yaml 定义了YOLOv5s网络结构的定义文件 yaml的主要内容 参数配置 nc: 80 类别数量 depth_multiple: 0.33 模型深度缩放因子 width_multiple: 0.50 控制卷积特征图的通道个数 anchors配…

JSON(详解)

目录 什么是JSON&#xff1f; 哪里会用到JSON&#xff1f; JSON的特点 JSON的优点 JSON的缺点 JSON和cJSON的关系 什么是JSON&#xff1f; JSON&#xff08;JavaScript Object Notation&#xff09;是一种轻量级的数据交换格式。它以易于阅读和编写的文本格式来存储和表示…

Linux mkdir命令:创建目录(文件夹)

mkdir 命令&#xff0c;是 make directories 的缩写&#xff0c;用于创建新目录&#xff0c;此命令所有用户都可以使用。mkdir 命令的基本格式为&#xff1a; [rootlocalhost ~]# mkdir [-mp] 目录名 -m 选项用于手动配置所创建目录的权限&#xff0c;而不再使用默认权限。 -p…

shell算数运算指令、

1.shell算数运算的指令 (( )) $[ ] let expr expr的字符串运算 例子&#xff1a; 2.shell的if分支结构

1624. 两个相同字符之间的最长子字符串

1624. 两个相同字符之间的最长子字符串 java代码&#xff1a; class Solution {public int maxLengthBetweenEqualCharacters(String s) {int[] hash new int[26];Arrays.fill(hash, -1); // fill是Arrays静态方法int max -1;for (int i 0; i < s.length(); i) { // 对…