C++——作用域和可访问性

一、 命名空间 嵌套命名空间 namespace B{ namespace C{ extern int x; // 声明变量 void g(int); // 声明函数原型 void g(long){ cout << "B::C::g(long)\n"; } }; }; using B::C::x; // 声明引用变量 x,把它引入到当前作用域 // 就不能在当前作用域定义同名变量了 using namespace B; // 引用命名空间,但不会把函数和变量引入到当前作用域 // 在当前作用域中仍然可以定义同名的变量和函数 using B::C::g; // 声明引用 void g(int) 和 void g(long) // 将函数名为 g 的所有函数都引入到当前作用域 namespace B::C{ int y = 1; int x = 2; // 定义变量 x void g(int a){ // 定义函数 void g(int) cout << "B::C::g(int)\n"; } void g(void){ cout << "B::C::g(void)\n"; } }; static int xx = 1; class A{ public: int xx; A(int xx){ A::xx = xx; } }; int main() { static int xx = 2; A a(3); cout << a....

September 9, 2022 · 2 min · Rick Cui

C++——父类与子类、基类与派生类

public 继承的派生类和基类具有父子关系 具有父子关系的派生类指针或对象可以不用进行强制类型转换,直接赋值给基类指针或引用 非 public 继承的 派生类指针 要通过强制类型转换(reinterpret_cast 或者 (Base*))的方式才能赋值给 父类指针 在 派生类内部和派生类的友元函数 中可以用 父类指针 或 父类引用 直接指向 子类指针或对象,也可以直接将 子类对象赋值给父类对象 在其它地方,不能将 非 public 继承 的 派生类对象 赋值给父类对象或引用,提示 不可访问的基类,但可以通过 (Base&&) 这种强制类型转换的方式将派生类对象转换为基类的右值引用,且支持多态(VS 无法编译通过) 父类的析构函数必须是虚函数 即使父类的析构函数不是虚函数,在栈上定义的子类对象销毁时也会调用父类的析构函数 指针、右值引用、左值引用都支持多态 对象间赋值转换不支持多态 #include <iostream>using namespace std; class A{ public: ~A() = default; //1) // A(){} //2) virtual void f(){ cout << "A::f()\n"; } }; class B: A{ friend void friendFun(); void f(){ cout << "B::f()\n"; } public: A* getA(){ // 派生类内部函数可构成父子关系 return this; } }; void friendFun(){ // 派生类友元函数内可构成父子关系 A* p = new B; p->f(); } int main() { // A* p = new B; // error: ‘A’ is an inaccessible base of ‘B’ A* p = (A*)new B; // right B b; A* pp = b....

September 6, 2022 · 4 min · Rick Cui

C++——派生类修改基类成员的访问权限

案例一: class A { int x, y; public: int getx() { return x; } protected: int gety() { return y; } }; class B : private A /* public A */ /* protected A */{ bool visible; public: using A::getx; A::gety; // deprecated }; 案例二: class MyList { struct Node { int v; Node* next; Node(int v, Node* n) { this->v = v; next = n; } ~Node() { cout << "~Node()\n"; delete next; next = nullptr; } } *head; public: MyList() { head = nullptr; } ~MyList() { if (head !...

September 4, 2022 · 1 min · Rick Cui

C++——Const、volatile、mutable

含有私有 const 实例数据成员的类必须定义构造函数,且该实例数据成员必须通过构造函数参数列表初始化 虽然 this 是隐含参数,也可以通过添加 const、volatile 修饰符实现函数重载 成员变量的类型会随着对象实例的类型变化而变化,比如一个 volatile int 类型的成员变量,如果对象实例为 const 的,则此时成员变量的类型为 const volatile int 经实验,mutable 不可以和 static、const 一起使用,但可以与 volatile 搭配使用

September 3, 2022 · 1 min · Rick Cui

C++——成员指针

实例成员指针 实例成员指针是指向实例成员的指针,可分为实例数据成员指针和实例函数成员指针 构造函数不能被显式调用且只能执行一次,所以不能有指向构造函数的实例成员指针 运算符为 .* 和 ->* 实例成员指针是成员相对于对象首地址的偏移,不是真正代表地址的指针 实例成员指针不能移动 实例成员指针不能转换类型 静态成员指针 静态成员指针前不用加类作用域 静态数据成员指针与普通的变量指针相同 静态函数成员指针与普通的函数指针相同 案例 静态成员指针存放成员地址,实例成员指针存放成员偏移 静态成员指针可以移动,实例成员指针不能移动 静态成员指针可以强制类型转换,实例成员指针不能强制转换类型 class Crowd { public: int a; // 表示在本类中不会修改此变量 // 但其它进程有可能会修改,表示会有多进程并发 volatile int b; // C++17 支持 // 使用 inline、const 修饰 static 变量可在类体内进行初始化 const static int j = 3; static int num; public: Crowd(); Crowd(int x); ~Crowd(); // 类体内函数定义 // 会被内联处理 int f() { b++; cout << "F()\n"; return b; } // const this 指针,参数类型不同,所以可被重载 int f()const { cout << "const F()\n"; return b; } static int getNum(); static Crowd& dec(Crowd& a); }; // 静态成员变量类体外初始化 int Crowd::num = 0; Crowd::Crowd() { a = 0; b = 0; Crowd::num++; cout << "Crowd()\n"; } Crowd::Crowd(int x): a(x) { b = 0; Crowd::num++; cout << "Crowd(int)\n"; } Crowd::~Crowd() { Crowd::num--; } int Crowd::getNum() { return Crowd::num; } Crowd& Crowd::dec(Crowd& a) { a....

September 3, 2022 · 2 min · Rick Cui