友元函数与友元类

友元利弊: 友元不是类的成员但能访问类中的私有成员。友元的作用在于提高程序的运行效率,但也破坏了类的封装。 注意事项: (1)友元关系不能被继承; (2)友元关系是单向的,不具有交换性; (3)友元关系不具有传递性; 一、友元函数 类的友元函数是定义在类外部,但有权访问类的所有私有(private)成员和保护(protected)成员 尽管友元函数的原型有在类的定义中出现过,但是 友元函数并不是成员函数 this 指针是所有成员函数的隐含参数。因此,在成员函数内部,它可以用来指向调用对象 友元函数没有 this 指针,因为友元不是类的成员。只有成员函数才有 this 指针 1. 友元函数是全局函数 class A { friend void printA(const A &a); public: void printA(); private: string name {"C++"}; int id {1024}; }; void A::printA(){ cout << "name = " << this->name << "\tid = " << this->id << endl; } // 请注意:printA() 不是任何类的成员函数 void printA(const A &a){ cout << "name = " << a....

December 24, 2021 · 2 min · Rick Cui

构造、拷贝构造、赋值构造

结论: 拷贝构造函数是函数,赋值运算符是运算符的重载; 拷贝构造函数会生成新的类对象,赋值运算符不会; 拷贝构造函数是用一个已存在的对象去构造一个不存在的对象;而赋值运算符重载函数是用一个存在的对象去给另一个已存在并初始化过的对象进行赋值; 若接受返回值的对象已经初始化过,则会调用赋值运算符,且该对象还会调用析构函数,当对象中包含指针时,会使该指针失效,因此需要重载赋值运算符,使用类似深拷贝或移动构造函数的方法赋值,才能避免指针失效。 如果只有显示的构造函数,系统会提供默认的拷贝构造; 如果显示提供了拷贝构造,系统就不会提供默认的无参构造了,用户必需显示提供构造函数; 当既没有显式的构造函数,也没有拷贝构造时,系统才会提供默认的无参构造; 显示提供拷贝构造就必需显示提供构造函数; 显示提供赋值运算符重载就必需显示提供拷贝构造; 成员初始化列表 使用成员变量初始化列表,少了一次调用默认构造函数的过程,提高效率 常量成员,因为常量只能初始化不能赋值,所以必须放在初始化列表里面 引用类型,引用必须在定义的时候初始化,并且不能重新赋值,所以也要写在初始化列表里面 成员变量初始化的顺序跟在初始化列表的顺序无关,与变量声明的顺序有关 测试类 class A { public: A(){ cout << "default constructor" << endl; cout << "adrres: " << this << "\tpoint x: " << x << "\ty: " << y << endl; } A(int t){ x = new int(0); y = t; cout << "second constructor" << endl; cout << "adrres: " << this << "\tpoint x: " << x << "\ty: " << y << endl; } A(const A &a){ cout << "const copy constructor" << endl; cout << "adrres: " << this << "\tpoint x: " << x << "\ty: " << y << endl; this->x = a....

December 23, 2021 · 4 min · Rick Cui

函数重载、重写、隐藏、模板

重载: 在同一作用域中,两个函数名相同,但是参数列表不同(个数、类型、顺序),返回值类型没有要求; 重写(覆盖): 子类继承了父类,父类中的函数是虚函数,在子类中重新定义了这个虚函数,这种情况是重写或覆盖; 重定义: 派生类中函数与基类中的函数同名(形参没有要求),但是这个函数在基类中并没有被定义为虚函数 隐藏: 派生类中重定义了父类的函数,此时基类的函数会被隐藏; 模板: 函数模板是一个通用函数,函数的类型和形参不直接指定而用虚拟类型来代表,只适用于 参数个数相同而类型不同 的函数。 构造函数可以被重载,析构函数不可以被重载。因为构造函数可以有多个且可以带参数, 而析构函数只能有一个,且不能带参数 1、重载 类的静态函数也可以重载; 形参中一级指针和二级指针被认为是不同类型的参数; class A{ public: A(int a){ m_a = a; } void print(){ cout << "print()" << "m_a = " << m_a << endl; } void freeP(A ** p){ if(p == NULL){ return; } if(*p != NULL){ free(*p); *p = NULL; } } void freeP(A * p){ if(p != NULL){ free(p); p = NULL; } } static void printS(){ cout << "printS() s_a = " << s_a << endl; } static void printS(int s){ cout << "printS(int s) " << s_a * s << endl; } static void printS(void *p, int s){ cout << "printS(void *p, int s) " << ((A*)p)->m_a * s << endl; } static int s_a; private: int m_a; }; int A::s_a = 0; int main( ) { A *a = new A(1); a->printS(a, 20); a->print(); A::s_a = 10; a->printS(); a->printS(10); a->freeP(a); if(a == NULL){ cout << "*a is not valid" << endl; return 0; } cout << "*a is valid" << endl; a->print(); return 0; } 输出:...

December 23, 2021 · 2 min · Rick Cui

inline 内联函数

当一个函数被声明为内联函数之后,在编译阶段,编译器会用内联函数的函数体取替换程序中出现的内联函数调用表达式,而其他的函数都是在运行时才被替换,这其实就是用空间换时间,提高了函数调用的效率。同时,内联函数具有几个特点: 适用于函数体积很小并频繁使用的函数 内联函数中不可以出现循环、递归或开关操作 内联函数的声明必须在函数定义之前 内联函数的定义必须出现在内联函数的第一次调用前 在类中声明同时定义的成员函数(除了虚函数)会自动隐式的当成内联函数 虚函数可以是内联函数,但是当虚函数表现多态性的时候不能内联 优点: 内联函数在被调用处进行代码展开,省去了参数压栈、跳转返回、栈帧开辟与回收,结果返回等操作,从而提高程序运行速度; 内联函数相比宏函数来说,在代码展开时,会做安全检查或自动类型转换,而宏定义则不会; 在类中声明同时定义的成员函数,自动转化为内联函数,因此内联函数可以访问类的成员变量,宏定义则不能; 内联函数在运行时可调试,而宏定义不可以。 缺点: 代码膨胀,消耗了更多的内存空间; inline 函数无法随着函数库升级而升级。inline函数的改变需要重新编译,不像 non-inline 可以直接链接; 内联函数其实是不可控的,它只是对编译器的建议,是否对函数内联,决定权在于编译器; 不能对函数进行取址操作

December 23, 2021 · 1 min · Rick Cui

C 与 C++ 的差异

C++ 是 C 的超集和增强,校验更加严格 C 主要是面向过程,C++ 是面向对象,面向过程是函数驱动,面向对象是对象驱动 1 新增命名空间 给{}作用域起了个名称,后面不用加分号; 命名空间可以嵌套 namespace X { namespace Y { } } 2 新增引用类型 引用在一定程度上可以替代指针,作用与常指针类似 int * const a 引用没有定义,是一种关系声明,声明它和原有某一变量(实体)的关系, 故而类型与原类型保持一致,且不分配内存,与被引用的变量有相同的地址 声明时必须初始化,一经声明,不可变更 可对引用再次引用,多次引用的结果是某一变量具有多个别名 & 符号在 = 号左边是引用,在 = 号右边为取地址 3 枚举检测增强 不能将整型隐式转化为枚举 4 变量定义增强 C++ 变量不必都声明在函数顶部,可以随使用随定义 5 全局变量定义检测严格 C 全局变量重复定义,C++ 不可以,全局变量检测增强 // C 语言 int g_val; // bss段 int g_val = 10; // data段 6 函数形参个数和函数返回值检测增强 // C 语言 f() // 默认返回值 int { return 10; } int g(int a) { return 10; } // 调用 g(10, 20, 30, 40); // 可编译通过,但是有警告 7 struct 结构体增强 功能与类基本等同,只不过 class 默认是 private 权限,struct 默认是 public 权限 // C 语言声明结构体变量 struct Student s; // C++ 语言声明结构体变量 Student s; 8 新增 bool 关键字,1 个字节 C 用 0 表示 false,非 0 表示 true C++ 中 bool 为 1 个字节,但是只有 true 和 false 两个值 9 三目运算符增强(语法糖) C 中三目运算符不可以当左值 // C 语言 int a = 10, b = 20; ((a < b) ?...

December 22, 2021 · 2 min · Rick Cui