C++杂项记录

本文最后更新于:2022年10月18日 下午

相同class的各个对象互为友元

C++面向对象高级编程(侯捷) P4 参数传递与返回值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class complex{
public:
complex(double r=0, double i=0)
:re(r), im(i)
{ }

double func(const complex& param){
return param.re + param.im;
}
private:
double re, im;
}

int main(){
complex cl(2,1);
complex c2;
c2.func(c1);
}

无须手动声明即为友元,如上述代码中func函数可以访问相同类的其他对象的私有数据。

C++关键字

explicit关键字

explicit关键字的作用是防止类构造函数的隐式自动转换。

explicit关键字只对有一个参数的类构造函数有效(或仅第一个参数没有默认值)。如果类构造函数参数大于或等于两个时, 是不会产生隐式转换的, 所以explicit关键字也就无效了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class A{
A(int size){
//...
}
A(string s){
//...
}
}
class B{
explicit B(int size){
//...
}
B(string s){
//...
}
}
int main(){
A a1="test";//OK
A a2=10;//OK
B b1="test";//OK
B b2=10;//FAIL 禁止隐式调用
}

volatile关键字

volatile的本意是“易变的”。volatile提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据。

如果没有volatile关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值,如果这个变量由别的程序更新了的话,将出现不一致的现象。

优化器在用到volatile变量时必须每次都小心地重新读取这个变量的值,而不是使用保存到寄存器里的备份。

volatile适用于多线程应用中被几个任务共享的变量。

extern关键字

  • extern “C”

    在C++环境下使用C的函数时使用。

    C++在实现函数重载时会在编译时将函数名和形参列表编码在一起生成一个函数名称(也就是重载的函数对于编译器来说完全是不同名的函数),但是C不支持函数重载也就不存在编译器对函数名的处理,这导致C++编译器无法链接到C的库。加上extern "C"关键字则使C++编译器按C的规则编译,保持函数名,不生成中间函数名。

  • extern 变量

    标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义。

  • extern 函数

    暗示这个函数可能在别的源文件里定义。

mutable关键字

用于突破const的限制,使得不需要修改函数的不可变性也可以修改被修饰的变量。

using关键字

  • 别名语法 C++11

    优点:支持类型含有空格的情况、支持泛型。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // 重定义unsigned int
    typedef unsigned int uint_t;
    using uint_t = unsigned int;
    // 重定义std::map
    template <typename T>
    using str_map = map<string, T>;
    int main(){
    str_map<int> m;//map<string,int>
    }
  • using namespace 命名空间

    在后面的程序中直接使用此命名空间的元素。

  • 调整基类元素的访问权限

    当一个派生类私有继承基类时,基类的public和protected数据成员在派生类中是private的形式,如果想让这些继承而来的数据成员作为public或者protected成员,可以用using来重新声明。using声明语句中名字的访问权限由该using声明语句之前的访问说明符决定。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class Basic{
    public:
    int a;
    int b;
    };
    class Bulk : private Basic{
    public:
    using Basic::a;
    protected:
    using Basic::b;
    };

    上例中,Bulk类私有继承Basic,默认情况下,在Bulk中,成员a,b应该是private类型,不过,在上例中用using重新声明了a,b数据成员,使a成为public,使b成为protected。

  • 快速集成基类的部分重载函数

    因为派生类可以重载继承自基类的成员函数,所以如果派生类希望所有的重载版本对于它都是可见的,那么它就要覆盖所有版本或者一个也不覆盖。但是,有时一个类仅需要覆盖重载部分函数,若覆盖所有函数,就太繁琐了。
    那么此时,using就派上用场了。只要为重载的成员函数提供一条using声明,这样我们就无需覆盖基类中的每一个版本了。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class Basic{
    void func(){
    cout<<"func()1"<<endl;
    }
    void func(int a){
    cout<<"func()2"<<endl;
    }
    };
    class Bulk : public Basic{
    using Basic::func;
    };

    上例using声明指定一个名字而不指定形参列表,所以,一条基类成员函数的using声明语句就可以把该函数的所有重载实例添加到派生类作用域中。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!