IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> Essential C++学习笔记及源代码(第4章 基于对象编程风格) -> 正文阅读

[C++知识库]Essential C++学习笔记及源代码(第4章 基于对象编程风格)

第4章介绍了C++语言中使用Class进行基于对象的编程的方式

导言:一般而言,class由两部分组成:一组公开的(public)操作函数和运算符,以及一组私有的(private)实现细节。这些操作函数和运算符称为class的成员函数,并代表这个class的公开接口。身为class的用户只能访问其公开接口。这也就是我们使用string、vector等标准模板库的方式。例如,针对string的成员函数size(),我们只知道其原型声明,即参数列表为void,返回一个整数值。

1、Class的private实现细节可由成员函数的定义以及与class相关的任何数据组成。例如,假设string类对象的size()每次被调用,都会重新计算其字符串长度,那么就不需要任何相关的数据来存储这份信息,size()定义中可能利用for循环之类的遍历方式取得字符串长度。但如果string类对象想存储其字符串长度,就必须在每个class对象中定义一个private的数据成员,并在size()定义中将该值返回。每当字符串长度有所变动,这份private数据成员就必须被更新。

2、Class用户通常不会关心此等实现细节。身为一个用户,我们只利用其公开接口来进行编程。这种情形下,只要接口没有更改,即使实现细节重新构造,所有的应用程序代码也无须变动。

3、这一章我们学习将从class的使用提升至class的设计与实现。这正是C++程序员的主要工作。

本章作者使用了一个Triangular类来模拟一个class的实现,并教导读者在实现一个class的过程中需注意的细节。当私有成员有pointer成员时必须重载复制构造函数和赋值运算符防止内存越界。在本章最后引出一个例子简要体现第5章面向对象编程的含义。

附上笔者所写的课后练习答案。

//ch4_main.cpp

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

class Triangular_iterator
{
public:
    Triangular_iterator(int index) : _index(index - 1) {} //构造函数初始化iterator;
    bool operator==(const Triangular_iterator &) const;   //比较iterator是否相等;
    bool operator!=(const Triangular_iterator &) const;   //比较iterator是否不相等;
    int operator*() const;                                //指针解引用运算符;
    Triangular_iterator &operator++();                    //前置自增运算符;
    Triangular_iterator operator++(int);                  //后置自增运算符;

private:
    void check_integrity() const; //判断_index索引是否合法;
    int _index;
};

class Triangular
{
public:
    Triangular(int len = 1, int bp = 1);
    Triangular(const Triangular &);
    Triangular &operator=(const Triangular &rhs);
    //3个构造函数;

    int length() const { return _length; }
    int beg_pos() const { return _beg_pos; }
    int elem(int pos) const;
    //获取vector长度, 起始位置, pos位置的元素值;

    void length(int nlen) { _length = nlen; }
    void beg_pos(int npos) { _beg_pos = npos; }
    //更改Triangular的长度大小和起始位置;

    bool next(int &val) const;
    void next_reset() const { _next = 1; }
    //获取元素值和重置_next指针;

    static bool is_elem(int);
    static void gen_elements(int length);
    static void gen_elems_to_value(int value);
    static void display(int length, int beg_pos, ostream &os = cout);
    //只能访问静态成员, 此处访问的是成员vector<int> _elems;

    typedef Triangular_iterator iterator;
    Triangular_iterator begin() const
    {
        return Triangular_iterator(_beg_pos);
    }
    Triangular_iterator end() const
    {
        return Triangular_iterator(_beg_pos + _length);
    }

private:
    friend class Triangular_iterator; //作为Triangular类的iterator友元, 可访问private中的成员;
    int _length;
    int _beg_pos;
    mutable int _next;
    enum
    {
        _max_elems = 1024
    };
    static vector<int> _elems;
};

ostream &operator<<(ostream &os, const Triangular &rhs)
{
    os << "( " << rhs.beg_pos() << " , " << rhs.length() << " ) ";
    rhs.display(rhs.length(), rhs.beg_pos(), os);
    return os;
}

istream &operator>>(istream &is, Triangular &rhs)
{
    char ch1, ch2;
    int bp, len;

    is >> ch1 >> bp >> ch2 >> len;
    rhs.beg_pos(bp);
    rhs.length(len);
    rhs.next_reset();
    return is;
}

Triangular::Triangular(int len, int beg_pos) : _length(len > 0 ? len : 1), _beg_pos(beg_pos > 0 ? beg_pos : 1)
{
    _next = _beg_pos;
    int elem_cnt = _beg_pos + _length;
    if (_elems.size() < elem_cnt)
    {
        gen_elements(elem_cnt);
    }
}

Triangular::Triangular(const Triangular &rhs) : _length(rhs._length), _beg_pos(rhs._beg_pos), _next(rhs._next)
{
}

//计算所有元素之和
int sum(const Triangular &trian)
{
    if (0 == trian.length())
    {
        return 0;
    }
    int val, sum = 0;
    trian.next_reset(); //重置为起点开始累加;
    while (trian.next(val))
    {
        sum += val;
    }
    return sum;
}

int Triangular::elem(int pos) const
{
    return _elems[pos - 1];
}

bool Triangular::next(int &value) const
{
    if (0 == _next)
    {
        return false;
    }
    if (_next < _beg_pos + _length)
    {
        value = _elems[_next++];
        return true;
    }
    _next = 0;
    return false;
}

Triangular &Triangular::operator=(const Triangular &rhs)
{
    if (this != &rhs)
    {
        _length = rhs._length;
        _beg_pos = rhs._beg_pos;
        _next = 1;
    }
    return *this;
};

vector<int> Triangular::_elems; //定义一个静态vector;

bool Triangular::is_elem(int value)
{
    if (0 == _elems.size() || _elems[_elems.size() - 1] < value)
    {
        gen_elems_to_value(value);
    }
    return find(_elems.begin(), _elems.end(), value) != _elems.end();
}

void Triangular::gen_elements(int length)
{
    if (length < 0 || length > _max_elems)
    {
        cerr << "Triangular Sequence: oops: invalid size: ";
        cerr << length << " -- max size is ";
        cerr << _max_elems << endl;
        return;
    }
    if (_elems.size() < length)
    {
        int ix = _elems.size() ? _elems.size() + 1 : 1;
        while (ix <= length)
        {
            _elems.push_back(ix * (ix + 1) / 2); //添加元素直到vector长度大于等于length;
            ++ix;
        }
    }
    return;
}

void Triangular::gen_elems_to_value(int value)
{
    int ix = _elems.size();
    if (0 == ix)
    {
        _elems.push_back(1);
        ix = 1;
    }
    while (_elems[ix - 1] < value && ix < _max_elems)
    {
        _elems.push_back(ix * (ix + 1) / 2); //添加元素到vector中直到大于等于value;
        ++ix;
    }
    if (ix == _max_elems)
    {
        cerr << "Triangular Sequence: oops: value too large ";
        cerr << value << " --  exceeds max size of ";
        cerr << _max_elems << endl;
    }
    return;
}

void Triangular::display(int length, int beg_pos, ostream &os)
{
    if (length <= 0 || beg_pos <= 0)
    {
        cerr << "invalid parameters -- unable to fulfill request: ";
        cerr << length << ", " << beg_pos << endl;
        return;
    }
    int elems = beg_pos + length - 1;
    if (_elems.size() < elems)
    {
        gen_elements(elems);
    }
    for (int ix = beg_pos - 1; ix < elems; ++ix)
    {
        os << _elems[ix] << ' ';
    }
    return;
}

inline bool Triangular_iterator::operator==(const Triangular_iterator &rhs) const
{
    return _index == rhs._index; //判断2个Triangular类是否相等;
}

inline bool Triangular_iterator::operator!=(const Triangular_iterator &rhs) const
{
    return !(*this == rhs); //使用重载过的==运算符的非运算;
}

class iterator_overflow //声明一个异常类;
{
};

inline void Triangular_iterator::check_integrity() const
{
    if (_index > Triangular::_max_elems)
    {
        throw iterator_overflow(); //抛出一个异常类iterator_overflow;
    }
    if (_index > Triangular::_elems.size())
    {
        Triangular::gen_elements(_index); //添加元素到vector中直到长度大于等于_index;
    }
    return;
}

inline int Triangular_iterator::operator*() const
{
    check_integrity();
    return Triangular::_elems[_index]; //获取_index索引中的元素;
}

inline Triangular_iterator &Triangular_iterator::operator++()
{
    ++_index; //递增下标;
    check_integrity();
    return *this; //返回新值;
}

inline Triangular_iterator Triangular_iterator::operator++(int)
{
    Triangular_iterator tmp = *this; //存储先前值;
    ++_index;                        //递增下标;
    check_integrity();
    return tmp; //返回先前值;
}

//函数对象作用是比较小于等于的值;
class LessThan
{
public:
    LessThan(int val) : _val(val) {}
    int comp_val() const { return _val; }
    void comp_val(int nval) { _val = nval; }
    bool operator()(int value) const { return value < _val; }

private:
    int _val;
};

int count_less_than(const vector<int> &vec, int comp)
{
    int count = 0;
    LessThan lt(comp);

    for (int ix = 0; ix < vec.size(); ++ix)
    {
        if (lt(vec[ix])) //直接调用;
        {
            ++count;
        }
    }
    return count;
}

void print_less_than(const vector<int> &vec, int comp, ostream &os = cout)
{
    LessThan lt(comp);
    vector<int>::const_iterator iter = vec.begin();
    vector<int>::const_iterator it_end = vec.end();

    os << "elements less than " << lt.comp_val() << endl;
    while ((iter = find_if(iter, it_end, lt)) != it_end) //作为参数调用标准模板库函数find_if;
    {
        os << *iter << ' ';
        ++iter;
    }
    os << endl;
    return;
}

void prog1()
{
    char ch;
    int ival;
    bool more = true;

    while (more)
    {
        cout << "Enter value: ";
        cin >> ival;

        bool is_elem = Triangular::is_elem(ival);
        cout << ival;
        cout << (is_elem ? " is " : " is not ");
        cout << "an element in the Triangular series.\n";
        cout << "Another value? (y/n) ";
        cin >> ch;
        if (ch == 'n' || ch == 'N')
        {
            more = false;
        }
    }
    return;
}

void prog2()
{
    Triangular tri(20, 12);
    Triangular::iterator it = tri.begin();
    Triangular::iterator end_it = tri.end();

    cout << "Triangular Series of " << tri.length() << " elements\n";
    cout << tri << endl;
    while (it != end_it)
    {
        cout << *it << ' ';
        ++it;
    }
    cout << endl;
}

void prog3()
{
    int ia[16] = {17, 12, 44, 9, 18, 45, 6, 14,
                  23, 67, 9, 0, 27, 55, 8, 16};

    vector<int> vec(ia, ia + 16);
    int comp_val = 20;

    cout << "Number of elements less than ";
    cout << comp_val << " are ";
    cout << count_less_than(vec, comp_val) << endl;
    print_less_than(vec, comp_val);
    return;
}

void prog4()
{
    Triangular tri(6, 3);
    cout << tri << endl;

    Triangular tri2;
    cout << "Please enter as the example (3, 5): ";
    cin >> tri2;
    cout << tri2 << endl;
    return;
}

void prog5()
{
    Triangular tri(4, 3);
    Triangular::iterator it = tri.begin();
    Triangular::iterator end_it = tri.end();

    cout << "Triangular Series of " << tri.length() << " elements\n";
    cout << tri << endl;

    while (it != end_it)
    {
        cout << *it << ' ';
        ++it;
    }
    cout << endl;
    return;
}

int main()
{
    prog1();
    prog2();
    prog3();
    prog4();
    prog5();

    return 0;
}

//-----------------------------------------------------------;

//-----------------------------------------------------------;
//Practise 4.1 and 4.2.cpp

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

int main()
{
    Stack st;
    string str;

    while (cin >> str && !st.full())
    {
        st.push(str);
    }
    cout << "\nRead in " << st.size() << " strings!\n";
    cin.clear();
    cout << "what word to search for? ";
    cin >> str;
    bool found = st.find(str);
    int count = found ? st.count(str) : 0;
    cout << str << (found ? " is " : " isn\'t ");
    cout << "in the stack. ";
    if (found)
    {
        cout << "It occurs " << count << " times\n";
    }

    return 0;
}

//-----------------------------------------------------------;
//Stack.h

#ifndef STACK_H_
#define STACK_H_
#include <string>
#include <vector>
using namespace std;

class Stack
{
public:
    bool push(const string &);
    bool pop(string &elem);
    bool peek(string &elem);

    bool find(const string &elem) const;
    int count(const string &elem) const;

    bool empty() const { return _stack.empty(); }
    bool full() const { return _stack.size() == _stack.max_size(); }
    int size() const { return _stack.size(); }

private:
    vector<string> _stack;
};

#endif

//-----------------------------------------------------------;
//Stack.cpp

#include <algorithm>
#include "Stack.h"

bool Stack::pop(string &elem)
{
    if (empty())
    {
        return false;
    }
    elem = _stack.back();
    _stack.pop_back();
    return true;
}

bool Stack::peek(string &elem)
{
    if (empty())
    {
        return false;
    }
    elem = _stack.back();
    return true;
}

bool Stack::push(const string &elem)
{
    if (full())
    {
        return false;
    }
    _stack.push_back(elem);
    return true;
}

bool Stack::find(const string &elem) const
{
    return std::find(_stack.begin(), _stack.end(), elem) != _stack.end();
}

int Stack::count(const string &elem) const
{
    return std::count(_stack.begin(), _stack.end(), elem);
}

//-----------------------------------------------------------;

//-----------------------------------------------------------;
//Practise4.3.cpp

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

class globalWrapper
{
public:
    static int tests_passed() { return _tests_passed; }
    static int tests_run() { return _tests_run; }
    static int version_number() { return _version_number; }
    static string version_stamp() { return _version_stamp; }
    static string program_name() { return _program_name; }

    static void tests_passed(int nval) { _tests_passed = nval; }
    static void tests_run(int nval) { _tests_run = nval; }
    static void version_number(int nval) { _version_number = nval; }
    static void version_stamp(const string &nstamp) { _version_stamp = nstamp; }
    static void program_name(const string &npn) { _program_name = npn; }

private:
    static string _program_name;
    static string _version_stamp;
    static int _version_number;
    static int _tests_run;
    static int _tests_passed;
};

string globalWrapper::_program_name;
string globalWrapper::_version_stamp;
int globalWrapper::_version_number;
int globalWrapper::_tests_run;
int globalWrapper::_tests_passed;

int main()
{
    if (globalWrapper::program_name().empty())
    {
        globalWrapper::program_name("ex_4_3");
        globalWrapper::version_number(1);
        globalWrapper::version_stamp("A1-OK");
    }
    if (globalWrapper::program_name() == "ex_4_3")
    {
        cout << "globalWrapper seems to work ok\n";
    }
    else
    {
        cout << "Hmm. globalWrapper doesn't seem to be correct\n";
    }

    return 0;
}

//-----------------------------------------------------------;

//-----------------------------------------------------------;
//Practise4.4.cpp

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

class UserProfile
{
public:
    enum Level
    {
        Beginner,
        Intermediate,
        Advanced,
        Professional
    };
    UserProfile();
    UserProfile(string login, Level = Beginner) : _login(login), _user_level(level), _times_logged(1), _guesses(0), _correct_guesses(0) {}
    bool operator==(const UserProfile &) { return _login == rhs._login && _user_name == rhs._user_name; }
    bool operator!=(const UserProfile &rhs) { return !(*this == rhs); }

    //以下函数用来读取数据;
    string login() const { return _login; }
    string user_name() const { return _user_name; }
    int login_count() const { return _times_logged; }
    int guess_count() const { return _guesses; }
    int guess_correct() const { return _correct_guesses; }
    double guess_average() const { return _guesses != 0.0 ? double(_correct_guesses) / double(_guesses) * 100 : 0.0; }
    //实时计算猜对百分比;
    string level() const;

    //以下函数用来写入数据;
    void reset_login(const string &val) { _login = val; }
    void user_name(const string &val) { _user_name = val; }
    void reset_level(const string &);
    void reset_level(Level newlevel) { _user_level = newlevel; }
    void reset_login_count(int val) { _times_logged = val; }
    void reset_guess_count(int val) { _guesses = val; }
    void reset_guess_correct(int val) { _correct_guesses = val; }
    void bump_login_count(int cnt = 1) { _times_logged += cnt; }
    void bump_guess_count(int cnt = 1) { _guesses += cnt; }
    void bump_guess_correct(int cnt = 1) { _correct_guesses += cnt; }

private:
    string _login;        //登陆记录;
    string _user_name;    //实际姓名;
    int _times_logged;    //登入次数;
    int _guesses;         //猜过次数;
    int _correct_guesses; //猜对次数;
    Level _user_level;    //等级;
};

inline UserProfile::UserProfile() : _login("guest"), _user_level(Beginner), _times_logged(1), _guesses(0), _correct_guesses(0)
{
    static int id = 0;
    ++id;
    //对于guest加入一个独一无二的会话标识符;
    _login += to_string(id);
}

inline string UserProfile::level() const
{
    static string _level_table[4] = {"Beginner", "Intermediate", "Advanced", "Professional"};
    return _level_table[_user_level];
}

ostream &operator<<(ostream &os, const UserProfile &rhs)
{
    os << rhs.login() << ' ';
    os << rhs.level() << ' ';
    os << rhs.login_count() << ' ';
    os << rhs.guess_count() << ' ';
    os << rhs.guess_correct() << ' ';
    os << rhs.guess_average() << endl;
    return os;
}

istream &operator>>(istream &is, UserProfile &rhs)
{
    string login, level;
    int lcount, gcount, gcorrect;

    is >> login >> level;
    is >> lcount >> gcount >> gcorrect;
    rhs.reset_login(login);
    rhs.reset_level(level);
    rhs.reset_login_count(lcount);
    rhs.reset_guess_count(gcount);
    rhs.reset_guess_correct(gcorrect);
    return is;
}

inline void UserProfile::reset_level(const string &level)
{
    if (level == "Intermediate")
    {
        _user_level = Intermediate;
    }
    else if (level == "Advanced")
    {
        _user_level = Advanced;
    }
    else if (level == "Professional")
    {
        _user_level = Professional;
    }
    else
    {
        _user_level = Beginner;
    }
    return;
}

int main()
{
    UserProfile anon;
    cout << anon;

    UserProfile anon_too;
    cout << anon_too;

    UserProfile anna("AnnaL", UserProfile::Professional);
    cout << anna;

    anna.bump_guess_count(27);
    anna.bump_guess_correct(25);
    anna.bump_login_count();
    cout << anna;

    cin >> anon;
    //输入: robin Intermediate 1 8 3
    cout << anon;

    return 0;
}

//-----------------------------------------------------------;

//-----------------------------------------------------------;
//Practise4.5.cpp

#include <iostream>
using namespace std;

typedef float elemType;
class Matrix
{
public:
    Matrix(elemType = 0.0f, elemType = 0.0f, elemType = 0.0f, elemType = 0.0f,
           elemType = 0.0f, elemType = 0.0f, elemType = 0.0f, elemType = 0.0f,
           elemType = 0.0f, elemType = 0.0f, elemType = 0.0f, elemType = 0.0f,
           elemType = 0.0f, elemType = 0.0f, elemType = 0.0f, elemType = 0.0f);
    Matrix(const elemType *);
    void operator+=(const Matrix &);
    elemType &operator()(int row, int column)
    {
        return _matrix[row][column];
    }
    int rows() const { return 4; }
    int cols() const { return 4; }
    elemType operator()(int row, int column) const
    {
        return _matrix[row][column];
    }
    ostream &print(ostream &) const;

private:
    friend Matrix operator+(const Matrix &, const Matrix &);
    friend Matrix operator*(const Matrix &, const Matrix &);
    elemType _matrix[4][4];
};

inline ostream &operator<<(ostream &os, const Matrix &m)
{
    return m.print(os);
}

Matrix operator+(const Matrix &m1, const Matrix &m2)
{
    Matrix result(m1);
    result += m2;
    return result;
}

Matrix operator*(const Matrix &m1, const Matrix &m2)
{
    Matrix result;
    for (int ix = 0; ix < m1.rows(); ix++)
    {
        for (int jx = 0; jx < m1.cols(); jx++)
        {
            result(ix, jx) = 0;
            for (int kx = 0; kx < m1.cols(); kx++)
            {
                result(ix, jx) += m1(ix, kx) * m2(kx, jx);
            }
        }
    }
    return result;
}

void Matrix::operator+=(const Matrix &m)
{
    for (int ix = 0; ix < 4; ++ix)
    {
        for (int jx = 0; jx < 4; ++jx)
        {
            _matrix[ix][jx] += m._matrix[ix][jx];
        }
    }
    return;
}

ostream &Matrix::print(ostream &os) const
{
    int cnt = 0;
    for (int ix = 0; ix < 4; ++ix)
    {
        for (int jx = 0; jx < 4; ++jx, ++cnt)
        {
            if (cnt && !(cnt % 8))
            {
                os << endl;
            }
            os << _matrix[ix][jx] << ' ';
        }
    }
    os << endl;
    return os;
}

Matrix::Matrix(elemType a11, elemType a12, elemType a13, elemType a14,
               elemType a21, elemType a22, elemType a23, elemType a24,
               elemType a31, elemType a32, elemType a33, elemType a34,
               elemType a41, elemType a42, elemType a43, elemType a44)
{
    _matrix[0][0] = a11, _matrix[0][1] = a12;
    _matrix[0][2] = a13, _matrix[0][3] = a14;
    _matrix[1][0] = a21, _matrix[1][1] = a22;
    _matrix[1][2] = a23, _matrix[1][3] = a24;
    _matrix[2][0] = a31, _matrix[2][1] = a32;
    _matrix[2][2] = a33, _matrix[2][3] = a34;
    _matrix[3][0] = a41, _matrix[3][1] = a42;
    _matrix[3][2] = a43, _matrix[3][3] = a44;
    return;
}

Matrix::Matrix(const elemType *array)
{
    for (int ix = 0; ix < 4; ++ix)
    {
        for (int jx = 0; jx < 4; ++jx)
        {
            _matrix[ix][jx] = *(array++);
        }
    }
    return;
}

int main()
{
    Matrix m;
    cout << m << endl;

    elemType ar[16] = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
                       0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
    elemType ar2[16] = {1.3f, 0.4f, 2.6f, 8.2f, 6.2f, 1.7f, 1.3f, 8.3f,
                        4.2f, 7.4f, 2.7f, 1.9f, 6.3f, 8.1f, 5.6f, 6.6f};

    Matrix identity(ar);
    cout << identity << endl;

    Matrix m2(identity);
    m = identity;
    cout << m2 << endl;
    cout << m << endl;

    Matrix m3(ar2);
    cout << m3 << endl;

    Matrix m4 = m3 * identity;
    cout << m4 << endl;

    Matrix m5 = m3 + m4;
    cout << m5 << endl;

    m3 += m4;
    cout << m3 << endl;

    return 0;
}

//-----------------------------------------------------------;

//--------------------------------------------2021年7月21日 ----------------------------------------------------

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-07-22 13:57:27  更:2021-07-22 13:58:53 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/2 2:11:14-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码