记录C++学习获得的经验点 2018/6/10-2018/6/16

类的一些特性

知识点1:可通过typedef或using类可以自定义某种类型别名在类中

知识点2:如果我们需要合成的默认构造函数,在空列表的构造函数后加上=default即可

知识点3:类的成员也可以重载,参数列表数量或者类型上不同

知识点4:在变量前加关键字mutable,变为可变数据成员,即使是在一个const的对象函数中也可以被修改

知识点5:类内初始值,直接用=赋予的方式是C++11新特性,也就是VS2013以上的版本才支持

知识点6:当某个数据成员在构造函数初始化列表中忽略,它将以默认构造函数的方式隐式初始化,但需要有一个初始化值,否则应该显式的初始化

为什么使用size_type类型

机器无关的(machine-independent)。
与unsigned型(unsigned int或unsigned long)具有相同的含义,而且可以保证足够大可存储任意string对象的长度。
为了使用由string类型定义的size_type类型,程序员必须加上作用域操作符来说明所使用的size_type类型是由string类定义的。
不要把size的返回值赋给一个int变量
unsigned型所能表示的最大正数值比对应的signed要大一倍。
这个事实表明size_type存储的string长度是int所能存储的两倍。
使用int变量的另一个问题是,有些机器上int变量的表示范围太小,甚至无法存储实际并不长的string对象。如在有16位int型的机器上,int类型变量最大只能表示32767个字符的string对象。
而能容纳一个文件内容的string对象轻易就会超过这个数字。因此,为了避免溢出,保存一个string对象size的最安全的方法就是使用标准库类型string:: size_type。

string类类型和许多其他库类型都定义了一些配套类型(companion type)。通过这些配套类型,库类型的使用就能和机器无关(machine-independent)。string::size_type定义为unsigned型,可以保证足够大的存储string对象的长度。   

注意,任何存储string的size操作结果的变量必须为string::size_type类型。尤其不能把size的返回值赋给一个int变量。(因为size返回的是一个unsigned类型,而int是signed类型。size能表达的大小是int的2倍)。

为什么使用inline函数

inline内联函数目的是为了解决程序中函数调用的效率问题。一般函数进行调用时,要将程序的执行权转到被调用的函数中,然后再返回到调用它的函数中;而内联函数在进行调用时,是将调用表达式用内联函数体来替换。
类中函数默认是inline函数
在类中对于公共代码使用私有功能函数,可以避免在多处使用同样的代码减少代码量,在调试时只需要修改定义的函数,在类内的函数为内联函数并不会产生额外的开销。

类的练习-字符方阵

using namespace std;
class Screen {
public:
    using pos = string::size_type;
    Screen() = default;
    Screen(pos wd, pos ht, char c) :height(ht), width(wd), contents(ht*wd, c) {}
    Screen(pos wd, pos ht) :height(ht), width(wd), contents(ht*wd, NULL) {}
    pos &getcursor() { return cursor; }
    char get() const { return contents[cursor]; }
    char get(pos r, pos c) { return contents[r*width + c]; }
    Screen &move(pos r, pos c) { cursor = ((r-1)*width + (c-1)); return *this; }
    Screen &set(char letter) { contents[cursor] = letter; return *this; }
    Screen &display(ostream &out) { do_display(out); return *this; }
    const Screen &display(ostream &out) const { do_display(out); return *this; }
private:
    pos cursor{ 0 };
    pos height{ 0 }, width{ 0 };
    string contents;
    void do_display(ostream &out) const {
        for (pos index = 0; index != height * width; ++index) {
            if (index%width == 0)out << endl;
            out << contents[index] << " ";
        }
    }
};
int main(int *argc, char *argv) {
    string::size_type row_num, column_num, resetrow,resetcolumn;
    char start_letter, resetletter;
    cout << "输入字符方阵的行数: ";cin >> row_num;
    cout << "输入字符方阵的列数: "; cin >> column_num;
    cout << "输入每个单位的初始化字符: "; cin >> start_letter;
    cout << "输入要改变字符单位的所在行数: "; cin >> resetrow;
    cout << "输入要改变字符单位的所在列数: "; cin >> resetcolumn;
    cout << "输入要改变成的字符: "; cin >> resetletter;
    Screen myScreen(row_num,column_num,start_letter);
    myScreen.move(resetrow, resetcolumn).set(resetletter).display(cout);
    cout << endl;
    myScreen.display(cout);
    cout << endl;
    return 0;
}

this指针的好与坏

优点:1:当需要将一个对象作为整体引用而不是引用对象的一个成员时,使用this,则该函数返回对调用该函数的对象的引用。

return *this;

2:可以非常明确地指出访问的是调用该函数的对象的成员,且可以在成员函数中使用与数据成员同名的形参。

class one{
public:
    void func(int member){
       this->member = member;
    }
private:
    int member;
};

缺点:不必要使用,代码多余。

class two{
public:
    void func(){
        cout<<member;//cout<<this->member;
    }
private:
    int member;
};

友元

如果一个类指定了友元类,则友元类的成员函数可以访问此类包括非公有成员在内的所有成员。
友元类
若在A类中有friend class B;
B类可以访问A类所有权限的成员
友元成员函数
若在A类中有friend void B::ItsFunction(Function's Parameter);
B中的ItsFunction函数可以访问A类的所有权限成员
声明友元函数对类的定义顺序的要求

①首先定义Window_mgr类,其中声明clear函数,但是不能定义它。在clear使用Screen的成员之前必须先声明Screen
②接下来定义Screen,包括对于clear的友元声明。
③最后定义clear,此时它才可以使用Screen的成员。

using namespace std;//这段代码用来练习如何声明友元函数
class Window_mgr {//但经过编译执行并不能正确地通过Window_mgr对象将某个screen对象清空(初始化字符),是由于类的定义顺序问题

public:
    using ScreenIndex = vector<Screen>::size_type;
    void clear(size_t);
private:
    vector<Screen> screens{ Screen(24,80,' ') };
};
class Screen {
    //friend class Window_mgr;

    friend void Window_mgr::clear(size_t);
public:
    using pos = string::size_type;
    Screen() = default;
    Screen(pos wd, pos ht, char c) :height(ht), width(wd), contents(ht*wd, c) {}
    Screen(pos wd, pos ht) :height(ht), width(wd), contents(ht*wd, NULL) {}
    pos &getcursor() { return cursor; }
    char get() const { return contents[cursor]; }
    char get(pos r, pos c) { return contents[r*width + c]; }
    Screen &move(pos r, pos c) { cursor = ((r-1)*width + (c-1)); return *this; }
    Screen &set(char letter) { contents[cursor] = letter; return *this; }
    Screen &display(ostream &out) { do_display(out); return *this; }
    const Screen &display(ostream &out) const { do_display(out); return *this; }
private:
    pos cursor{ 0 };
    pos height{ 0 }, width{ 0 };
    string contents;
    void do_display(ostream &out) const {
        for (pos index = 0; index != height * width; ++index) {
            if (index%width == 0)out << endl;
            out << contents[index] << " ";
        }
    }
};


void Window_mgr::clear(size_t i) {
    Screen &s = screens[i];
    s.contents = string(s.width*s.height, ' ');
}
int main(int *argc, char *argv) {


    return 0;
}

下面这段代码可以正确地通过Window_mgr对象将6x6字符都是n的screen对象归零/初始化(都变成星),因为没有用友元函数用的是友元类

using namespace std;
class Screen {
    friend class Window_mgr;
    //friend void Window_mgr::clear(size_t);
public:
    using pos = string::size_type;
    Screen() = default;
    Screen(pos wd, pos ht, char c) :height(ht), width(wd), contents(ht*wd, c) {}
    Screen(pos wd, pos ht) :height(ht), width(wd), contents(ht*wd, NULL) {}
    pos &getcursor() { return cursor; }
    char get() const { return contents[cursor]; }
    char get(pos r, pos c) { return contents[r*width + c]; }
    Screen &move(pos r, pos c) { cursor = ((r-1)*width + (c-1)); return *this; }
    Screen &set(char letter) { contents[cursor] = letter; return *this; }
    Screen &display(ostream &out) { do_display(out); return *this; }
    const Screen &display(ostream &out) const { do_display(out); return *this; }
private:
    pos cursor{ 0 };
    pos height{ 0 }, width{ 0 };
    string contents;
    void do_display(ostream &out) const {
        for (pos index = 0; index != height * width; ++index) {
            if (index%width == 0)out << endl;
            out << contents[index] << " ";
        }
    }
};

class Window_mgr {

public:
    using ScreenIndex = vector<Screen>::size_type;
    void clear(size_t);
    Screen &getScr(ScreenIndex i) { return screens[i]; }
    void addScr(Screen scr) { screens.push_back(scr); }
private:
    vector<Screen> screens{};
};

void Window_mgr::clear(size_t i) {
    Screen &s = screens[i];
    s.contents = string(s.width*s.height, '*');
}
int main(int *argc, char *argv) {
    Window_mgr Manager;
    Screen scr0(6,6,'n');
    Manager.addScr(scr0);
    Manager.getScr(0).display(cout);
    cout << endl;
    Manager.clear(0);
    Manager.getScr(0).display(cout);
    cout << endl;
    return 0;
}

其他注意事项
友元关系不具有传递性,每个类负责控制自己的友元类或友元函数。
对于要将一组重载函数设定为友元,对于每一个不同参数的版本都要分别声明。
在类内声明的友元必须在类内或者类外进行定义之后才可以使用。

关于Employee的类

#include"stdafx.h"
#include<iostream>
#include<string>
#include<vector>
#include<windows.h>
using namespace std;
class Employee {
private:
    const string Name;
    unsigned Age;
    const float BodyHeight;
    float Weight;
    const string MainSkill;
    string SecondSkill;
    unsigned salary;
    string character;
    float WorkEffect;
public:
    Employee(string name, unsigned age, float height, float weight,string main) :Name(name), Age(age), BodyHeight(height), Weight(weight),MainSkill(main) {
        cout << name << "的次级能力: ";cin >> SecondSkill;
        cout << name << "的目前薪水: "; cin >> salary;
        cout << name << "的性格描述: "; cin >> character;
        cout << name << "的工作贡献评分: "; cin >> WorkEffect;
    }
    void DisplayInfo() {
        cout << "\n姓名: " << Name;
        cout << "\n年龄: " << Age;
        cout << "\n身高: " << BodyHeight;
        cout << "\n体重: " << Weight;
        cout << "\n主要技能: " << MainSkill;
        cout << "\n次要技能: " << SecondSkill;
        cout << "\n目前薪水: " << salary;
        cout << "\n性格描述: " << character;
        cout << "\n工作贡献评分: " << WorkEffect<<endl;
    }
};
int main(int* argc, char *argv) {
    unsigned EmployeeCount;
    cout << "共有几位员工等待输入?     "; cin >> EmployeeCount;
    vector<Employee> EmployeesVec{};
    string tempname,tempmain; unsigned tempage; float tempheight, tempweight;
    for (unsigned i = 1; i <= EmployeeCount;i++) {
        system("cls");

        cout << "输入第" << i << "位员工的姓名: "; cin >> tempname;
        cout << tempname << "的年龄: "; cin >> tempage;
        cout << tempname << "的身高: "; cin >> tempheight;
        cout << tempname << "的体重: "; cin >> tempweight;
        cout << tempname << "的主要技能: "; cin >> tempmain;
        Employee tempEmployee(tempname,tempage,tempheight,tempweight,tempmain);
        EmployeesVec.push_back(tempEmployee);
    }
    cout << EmployeeCount << "位员工的信息录入完成。";
    char choice;
    cout << "是否输出所有员工信息?Y/N";
    if (cin >> choice) {
        switch (choice)
        {
        case 'y':
        case 'Y': {
            for (unsigned i = 0; i != EmployeeCount; i++) {
                EmployeesVec[i].DisplayInfo();
            }
            break;
        }
        default:
            break;
        }
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值