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

文章目录

      • 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,

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

第四章 文件管理 八、文件保护

目录 一、口令保护 1、定义&#xff1a; 2、优点&#xff1a; 3、缺点: 二、加密保护 1、定义&#xff1a; 2、例子&#xff1a; 2、优点&#xff1a; 3、缺点: 三、访问控制 1、定义&#xff1a; 2、精简的访问控制表&#xff1a; &#xff08;1&#xff09;定义&a…

JS实现商品SKU

<!DOCTYPE html> <html> <head><title>商品SKU</title><link rel"stylesheet" href"element/css/element.css"><style>*{ margin:0; padding:0px; box-sizing: border-box; }ul,li{ list-style-type: none;}bod…

LVS集群-NAT模式

集群的概念&#xff1a; 集群&#xff1a;nginx四层和七层动静分离 集群标准意义上的概念&#xff1a;为解决特定问题将多个计算机组合起来形成一个单系统 集群的目的就是为了解决系统的性能瓶颈。 垂直扩展&#xff1a;向上扩展&#xff0c;增加单个机器的性能&#xff0c;…

JVM 类的加载子系统

文章目录 类的加载过程加载阶段链接阶段初始化 类的加载器测试代码中获取对应的加载器获取加载器加载的路径不同类对应的加载器自定义加载器自定义加载器的方式 获取类的加载器的方式双亲委派机制双亲委派机制的好处 Java 的 SPI 机制1. 接口定义2. 具体实现3. 配置 META-INF/s…

StreamSaver.js入门教程:优雅解决前端下载文件的难题

本文简介 点赞 关注 收藏 学会了 本文介绍一个能让前端优雅下载大文件的工具&#xff1a;StreamSaver.js ⚡️ StreamSaver.js GitHub地址⚡️ 官方案例 StreamSaver.js 可用于实现在Web浏览器中直接将大文件流式传输到用户设备的功能。 传统的下载方式可能导致大文件的加…

centos ubantu IP一直变化,远程连接不上问题

文章目录 一、为什么IP地址会变1.主机DHCP导致 二、解决IP地址变化1.centos2.ubantu 总结 虚拟机能连接为互联网,但下一次启动IP地址再发生变化,无法使用ssh远程连接 一、为什么IP地址会变 1.主机DHCP导致 虚拟机系统(ubantu,centos…)启动后会向本地申请IP地址租约,租聘的I…

Java采集传感器数据,亲测有效!

背景 先说背景&#xff0c; 最近公司项目需要用到传感器&#xff0c;采集设备温湿度&#xff0c;倾斜角&#xff0c;电流…&#xff0c;公司采购采购了一个温湿度传感器给我们开发测试使用&#xff0c;如下图&#xff1a; 看着还挺精致有没有。 进入正题 有了这个温湿度传感器…

基于ChatGPT实现AI软件研发 | 神经网络 | 数据

计算机技术的发展和互联网的普及&#xff0c;使信息处理和传输变得更加高效&#xff0c;极大地改变了金融、商业、教育、娱乐等领域的运作方式。数据分析、人工智能和云计算等新兴技术&#xff0c;也在不断地影响和改变着各个行业。 如今&#xff0c;我们正在见证人工智能技术…

Redis(04)| 数据结构-压缩列表

压缩列表的最大特点&#xff0c;就是它被设计成一种内存紧凑型的数据结构&#xff0c;占用一块连续的内存空间&#xff0c;不仅可以利用 CPU 缓存&#xff0c;而且会针对不同长度的数据&#xff0c;进行相应编码&#xff0c;这种方法可以有效地节省内存开销。 但是&#xff0c;…

RK3568-pcie接口

pcie接口与sata接口 pcie总线pcie总线pcie控制器sata控制器nvme设备sata设备nvme协议ahci协议m-key接口b-key接口RC模式和EP模式 RC和EP分别对应主模式和从模式,普通的PCI RC主模式可以用于连接PCI-E以太网芯片或PCI-E的硬盘等外设。 RC模式使用外设一般都有LINUX驱动程序,安…

计算机操作系统重点概念整理-第四章 内存管理【期末复习|考研复习】

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

企业安全—DevSecOps概述详情

0x00 前言 SDL存在的问题在于体量过于庞大&#xff0c;不利于快速进行适配和进行&#xff0c;所以就有了DevSecOps&#xff0c;实际上是因为敏捷开发也就是DevOps的推进&#xff0c;并且坐上了云服务模式的火车&#xff0c;所以这一系列的东西都开始普及。DevSecOps作为DevOps…

PTE-写作 学习(一)

目录 PTE写作 写作技能 词汇积累 熟悉机经 pte写作考的就是态度 写作技能 看一段写一句 蓝色框里的单词是不可以使用的 &#xff0c;他们是副词&#xff0c;要添加新的句子 PTE写作 写作技能 词汇积累 熟悉机经 题库太窄 pte写作考的就是态度 写作技能 极有模板可…

【数据结构】选择排序

⭐ 作者&#xff1a;小胡_不糊涂 &#x1f331; 作者主页&#xff1a;小胡_不糊涂的个人主页 &#x1f4c0; 收录专栏&#xff1a;浅谈数据结构 &#x1f496; 持续更文&#xff0c;关注博主少走弯路&#xff0c;谢谢大家支持 &#x1f496; 直接选择、堆排序 1. 直接选择排序2…

泛微OA之获取每月固定日期

文章目录 1.需求及效果1.1需求1.2效果 2. 思路3. 实现 1.需求及效果 1.1需求 需要获取每个月的7号作为需发布日期&#xff0c;需要自动填充1.2效果 自动获取每个月的七号2. 思路 1.功能并不复杂&#xff0c;可以用泛微前端自带的插入代码块的功能来实现。 2.将这需要赋值的…

Redis -- 基础知识2

1.Redis客户端介绍 1.基础介绍 Redis是一种客户端-服务器结构的程序&#xff0c;通过网络进行互动 客户端的多种形态 1.自带了命令行客户端&#xff1a;redis-cil 2.图形化界面的客户端&#xff1a;依赖windows系统&#xff0c;连接服务器有诸多限制&#xff0c;不建议使用 3.基…

模拟算法及其优化

第一题 替换所有问号 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 class Solution { public:string modifyString(string s) {string ret;for(int i0;i<s.size();i){if(i0){if(s[i]?&&i1<s.size()){for(char aa;a<z;a){if(a!s…

J2EE项目部署与发布(Windows版本)

&#x1f3ac; 艳艳耶✌️&#xff1a;个人主页 &#x1f525; 个人专栏 &#xff1a;《Spring与Mybatis集成整合》《Vue.js使用》 ⛺️ 越努力 &#xff0c;越幸运。 1.单机项目的部署 1.1们需要将要进行部署的项目共享到虚拟机中 在部署项目之前&#xff0c;我们先要检查一下…

基于情感词典的情感分析方法

计算用户情绪强弱性&#xff0c;对于每一个文本都可以得到一个情感分值&#xff0c;以情感分值的正负性表示情感极性&#xff0c;大于0为积极情绪&#xff0c;小于0反之&#xff0c;绝对值越大情绪越强烈。 基于情感词典的情感分析方法主要思路&#xff1a; 1、对文本进行分词…

数据结构与算法基础(青岛大学-王卓)(9)

终于迎来了最后一部分(排序)了&#xff0c;整个王卓老师的数据结构就算是一刷完成了&#xff0c;但是也才是数据结构的开始而已&#xff0c;以后继续与诸位共勉 &#x1f603; (PS.记得继续守护家人们的健康当然还有你自己的)。用三根美味的烤香肠开始吧。。。 文章目录 排序基…