CppPrimer笔记 Chapter19 特殊工具与技术

CppPrimer笔记 Chapter19 特殊工具与技术

标签: Cpp



控制内存分配(19.1)

  • 可以自定义operator new但不能改变new 运算符
  • 对象的new与delete为隐式静态的的,而且不能操纵类的任何数据成员
  • 调用void *operator new(size_t)传入对象字节数.
    调用void *operator new[](size_t)传入数组中所有元素所需空间
  • 定位new如下,不分配任何内存,只是单纯返回指针实参并由new表达式在指定的地址初始化对象
    new(place_add)type[size]{braced initializer list
  • 调用析构函数会销毁对象,但不会释放内存
    明确 构造,析构 销毁内存,释放内存 之间的区别 可查找 RAII机制

运行时类型识别(RTTI)(19.2)

  • typeid(返回表达式类型)与dynamic_cast(将基类指针或引用安全地转换成派生类指针或引用)实现
    特别适用于:用基类指针或引用执行某个非虚函数的派生类操作.
  • dynamic_cast使用:
    • dynamic_cast<type*>(e)e必须为有效指针
    • dynamic_cast<type&>(e)e必须为左值
    • dynamic_cast<type&&>(e)e必不能为左值
      只允许:
      1. e是type的公有派生类(向上转换)
      2. e是type的公有基类(向下转换,需要指向派生类的基类指针)
      3. e与type相同
        这三种转换.
  • 若指针转换失败,则是0,引用转换失败,抛出异常bad_cast

  • typeid用于返回表达式的类型.那么可以在发生了指针上转型等过程中判断指向的对象是否相同
    dp = new Derived;
    Base*bp = dp;
    if (typeid(*bp) == typeid(*dp))
    {
        cout << "bp and dp point to same obj" << endl;
    }
    else
    {
        cout << "not same obj" << endl;
    }
  • 利用RTTI实现继承成体系中==
    由于使用虚继承体系,基类引用无法访问派生类中特有的对象
class Base{
    friend bool operator==(const Base&, const Base&);
public:
    int b;
protected:
    virtual bool equal(const Base&)const;
};

bool Base::equal(const Base &rhs) const
{
    return this->b == rhs.b;
}

class Derived :
    public Base{
public:
    string d;
protected:
    bool equal(const Base&)const override;
};

bool Derived::equal(const Base &rhs) const
{
    auto r = dynamic_cast<const Derived&>(rhs);
    return this->b == r.b && this->d == r.d;
}

bool operator==(const Base&lhs, const Base&rhs)
{
    //类型不同则返回false,否则调用equal
    return typeid(lhs) == typeid(rhs) && lhs.equal(rhs);
}

  • type_info类仅能通过typeid运算符创建,用于对象类型的比较等.
    void demo_type_info()
{
    int arr[10];
    Derived d;
    Base*p = &d;
    cout << typeid (42).name() << endl
        << typeid (arr).name() << endl
        << typeid (string).name() << endl
        << typeid (p).name() << endl
        << typeid(*p).name()<<endl;
}

枚举类型(19.3)

enum Tokens{INLINE = 128,VIRTUAL = 129};
//Tokens这样的全局枚举,会自动提升为int,注释第一个函数也不会报错
void ff(Tokens){ cout << "ff_Tokens" << endl; }
void ff(int){ cout << "ff_int" << endl; }
void ff(unsigned char){ cout << "ff_unsigned_char" << endl; }
void demo_enum()
{
    //前置声明
    enum intValues :unsigned  long long;//不限定作用域,必须制定成员类型
    enum class peppers;//限定作用域的可以使用默认成员类型Int
    enum color{ red, yellow, green};//没有class或struct,为全局的
    //enum stoplight{red,yellow,green}; 重定义枚举成员
    enum class peppers{red=5,yellow,green=9};
    color eyes = green;
    //peppers p = green; //error:peppers的枚举成员不在有效的作用域中,
                        //color::green在,但类型错误

    color har = color::red;
    peppers p2 = peppers::red;

    //默认情况下.枚举类型从0开始,之后成员为之前的枚举成员的值加1
    int x = yellow;//x = 1
    cout << x << endl;
    int y = (int)peppers::yellow;//限定作用域的枚举类型不会进行隐式转换
    cout << y << endl;

    enum intValues :unsigned long long{
        charTyp = 255, shortTyp = 65535, intTyp = 65535,
        longTyp = 4294967295UL, long_longTyp = 18446744073709551615ULL,
    };

    Tokens curTok = INLINE;
    ff(128);
    ff(INLINE);
    ff(curTok);
    unsigned char uc = VIRTUAL;
    ff(VIRTUAL);
    ff(uc);
}

类成员指针(19.4)

  • 初始化时,我们令其指向类的某个成员,但不指定该成员所属的对象,直到使用成员指针时,才提供成员所属对象
  • 使用数据成员指针
    //pdata可以指向一个常量(非常量)Screen对象的string成员
    const string Screen::*pdata;
    //利用返回数据成员指针的函数,用于获取私有类
    pdata = Screen::data();
    Screen myScreen, *pScreen = &myScreen;
    //使用数据成员指针
    auto s = myScreen.*pdata;//' '
    auto s2 = pScreen->*pdata;//' '
    cout << s << endl;
    cout << s2 << endl;

  • 成员函数与相应指针之间不像普通函数可以自动转换
  • 使用成员函数指针
    //调用运算符前括号不可少,由于调用运算符优先级高于指针向成员运算符的优先级
    char c1 = (pScreen->*pmf)();
    char c2 = (myScreen.*pmf2)(0, 0);

    //使用别名
    using Action =
        char(Screen::*)(Screen::pos, Screen::pos)const;
    Action get = &Screen::get;
    Screen& action(Screen&, Action = &Screen::get);
    //成员函数指针表
    myScreen.move(Screen::HOME);
    myScreen.move(Screen::DOWN);

  • 成员指针并不是可调用对象,利用function,mem_fn或bind产生可调用对象,实际上还是自动地在对象上调用函数指针
    vector<string*>pvec;
    //function< bool (const string*) > fp = &string::empty;
    //fp 接受一个指向string的指针, 然后使用->*调用empty
    //相当于if(((*it)->*p())it为一内部迭代器
    //find_if(pvec.begin(), pvec.end(), fp);
    //利用mem_fn可以从成员指针类型推断可调用对象类型
    auto f = mem_fn(&string::empty);
    find_if(pvec.begin(), pvec.end(), mem_fn(&string::empty));
    f(*pvec.begin());
    f(pvec[0]);
    //使用bind生产可调用对象
    auto it = find_if(pvec.begin(), pvec.end(),
        bind(&string::empty, _1));

嵌套类(19.5)

  • 嵌套类的名字在外层作用域中是可见的.二者相互之间没有特殊的访问权限
  • 嵌套类的静态成员定义将位于外层作用域之外
  • 外层类的对象与嵌套类的对象没有任何关系

union类型(19.6)

  • 不能含有引用类型的成员
  • 没有继承特性(不可做派生类,基类,无虚函数)
  • 由于为union的一个数据成员赋值会令其他数据成员变成未定义的状态,不可访问
  • 匿名的union视为一个当前作用域内可直接访问的对象.里面的对象可直接使用,可以认为是许多已定义了的对象共享一块内存.同时,不能包含受保护的成员或私有成员.
  • 类中的union含有类类型成员时,必须自己显示进行释放,拷贝,赋值操作.

局部类(19.7)

  • 局部类所有成员,包括函数都必须完整定义在类的内部,不允许声明静态数据成员.
  • 局部类只能访问外层作用域定义的类型名,静态变量与枚举成员.普通的局部变量不能被该局部类使用.
  • 局部类内的嵌套类也是局部类

固有的不可移植的特性(19.8)

  • 类可将(非静态)(一般为无符号数)数据成员定义成位域,一个位域中含有一定数量的二进制位.
  • 取地址符&不能用于位域

  • volatile表明它可能在程序控制或检测之外被改变.编译器不应该对这样的对象进行优化. 因而它其实与const也不冲突
  • voltile 限定符行为很像const.比如
    volatile int v; volatile int*ivp = &v;
    //error int *ip = &v; //必须使用指向volatile的指针
    但有一个重要区别:
    我们不能使用合成的拷贝/移动构造函数与赋值运算符初始化volatile对象或从volatile对象赋值.
  • 只有voltile函数才能被volatile对象调用

  • 链接指示来指出任意非C++函数所用的语言.
  • 编译器检查其调用方式与处理普通的C++函数的方式相同
  • 要求我们必须有权访问语言的编译器,并且这个编译器与当前C++编译器是兼容的
  • 链接指示不能出现在类定义或函数定义的内部,同样的链接指示必须出现在函数的每个声明中.
    extern "C" size_t strlen(const char *)
    extern "C" {
        int strcmp(const char*,const char*);
        char *strcat(char*,const char*);
    }
    extern "C"{
        #include<string.h>
    }
  • 链接指示对整个声明有效,也就是对函数而言,返回类型,形参等都是C的.它也不能使用C++中的类与对象.
  • C支持重载,因而一组重载中只会有一个是C的.凡是C不支持的那么都是不能使用的.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值