C++——异常的使用

普通函数、lambda表达式、函数模板和模板实例函数都可以定义异常接口 指针和引用类型的异常都可以支持多态 catch 的子类异常一定要写在父类异常的上面,catch 执行后就不会再执行后面的 catch 语句了 对于指针异常,如果不打算向上抛出,一定要记得 delete const volatile void * 可以捕获抛出的任何指针异常 ... 可以捕获抛出的任何异常 不引发任何异常,在函数后面添加 throw()、throw(void)、noexcept 建议将 noexcept 应用到任何绝不允许异常传播到调用堆栈的函数,当函数被声明为 noexcept 时,它使编译器可以在多种不同的上下文中生成更高效的代码 Exception.h struct A { int a = 1; virtual int getA()const { return a; } }; struct B : A { int a = 2; int getA()const override { return a; } }; #define cout cout<<__FILE__<<":"<<__LINE__<<": Exception: " void testException() { try { // 抛出子类指针类型的异常 //throw new B; // 抛出子类对象类型的异常 throw B(); } catch (const A e) { cout << e....

September 14, 2022 · 2 min · Rick Cui

C++——多继承与虚基类

案例一: class A { public: int a; A(int x) :a(x) { } }; class B : public A { public: B(int x) :A(x) { // 这里初始化的是派生树中正常的基类 A } }; class C { public: C() { } }; class D : virtual public A, public C { public: D(int x) :A(x) { } }; class E : /*public A,*/ public B, public D { // 不允许存在直接基类和间接虚基类的情况 public: E(int x) : A(x), B(x + 5), D(x + 10) { // error C2385: 对“A”的访问不明确 // 所以要使用 B::A(x) 或者 D::A(x) // 此时初始化的都是派生树中虚基类 A } }; int main(){ E e(0); //cout << e....

September 12, 2022 · 2 min · Rick Cui

C++——虚函数表与多态(派生类内存布局)

一、基类中有虚函数但不是虚继承 class A { public: A() { c(); } virtual ~A() { d(); } virtual void c() { cout << "Construct A\n"; } virtual void d() { cout << "Deconstruct A\n"; } }; class B : public A { public: B() { // 等价于 B() : A(){} c(); } ~B() { d(); } void c()override { cout << "Construct B\n"; } void d()override { cout << "Deconstruct B\n"; } }; int main() { B b; return 0; } Construct A Construct B Deconstruct B Deconstruct A 二、有虚继承 Linux 布局参考这里...

September 11, 2022 · 1 min · Rick Cui

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