C++ 学习(友元, 异常, 其他)
2015-12-01 09:48
274 查看
包含:
http://www.cnblogs.com/uniqueliu/archive/2011/08/01/2124261.html
友元类
如果某类B的成员函数会频繁的存取另一个类A的数据成员, 而A的数据成员的Private/Protectd限制造成B存取的麻烦, B只能通过A的Public的成员函数进行间接存取
把B做成A类的友元类,即A类向B类开放其Private/Protectd内容, 让B直接存取
友元类:一个类可以作另一个类的友元
友元类的所有成员函数都是另一个类的友元函数
友元类的声明:
friend class 类名;
友元类注意事项:
1、友元关系是单向的
2、友元关系不能被传递
3、友元关系不能被继承
4、有时候需要注意前向声明
嵌套类,局部类:
局部类
局部类是指在函数中定义类。
(c++不能在函数中定义函数。c++在类中定义的函数也就是成员函数。)这个类以及由它创建的对象,都局限在该函数作用域中;必须在类内实现所有的成员函数,不能拿到类外。因为函数是不可以嵌套定义的;若类内含有静态数据成员,必须在该函数外初始化;类内不可含有静态函数成员;类中不可使用包裹它的函数所定义的除静态外的局部变量。
局部类
局部类的另一个用途是用来实现类型转化
.内嵌类
是在类体内定义的又一个类。外面的类叫外围类。这个类以及由它创建的对象,都局限在外层类作用域中;
外界能否使用内层类,全在于访问权限;若能使用,定要以外围类::内层类格式来用;
是类组合演化的又一种类间关系,即组合或聚集成员不是产生于其它类,而是产生于内层类;内层类的成员函数,可以在类内实现,也可以在外层类之外实现;
内层类的成员函数对外围类的成员没有访问权,反之亦然
定义嵌套类的目的在于隐藏类名,减少全局的标识符,从而限制用户能否使用该类建立对象。这样可以提高类的抽象能力,并且强调了两个类(外围类和嵌套类)之间的主从关系。
其中,类B是一个嵌套类,类A是外围类,类B定义在类A的类体内。
2 对嵌套类的若干说明:
1、从作用域的角度看,嵌套类被隐藏在外围类之中,该类名只能在外围类中使用。如果在外围类的作用域内使用该类名时,需要加名字限定。
2、从访问权限的角度来看,嵌套类名与它的外围类的对象成员名具有相同的访问权限规则。不能访问嵌套类的对象中的私有成员函数,也不能对外围类的私有部分中的嵌套类建立对象。
3、嵌套类中的成员函数可以在它的类体外定义。
4、嵌套类中说明的成员不是外围类中对象的成员,反之亦然。嵌套类的成员函数对外围类的成员没有访问权,反之亦然。国此,在分析嵌套类与外围类的成员访问关系时,往往把嵌套类看作非嵌套类来处理。
异常
abort
于一个用C++写的程序,被加载至内存后运行,最终走向死亡。程序的死亡大致有三种:自然死亡,即无疾而终,通常就是main()中的一个return 0;自杀,当程序发现自己再活下去已经没有任何意义时,通常会选择自杀。当然,这种自杀也是一种请求式的自杀,即请求OS将自己毙掉。有两种方式:void exit(int status)和void abort(void)。他杀,同现实不同的是,程序家族中的他杀行径往往是由自己至亲完成的,通常这个至亲就是他的生身父亲(还是母亲?)。C++并没有提供他杀的凶器,这些凶器往往是由OS直接或者间接(通过一些进程库,如pthread)提供的。 自然死是最完美的结局,他杀是我们最不愿意看到的,自杀虽是迫不得已,但主动权毕竟还是由程序自己掌控的;abort被调用时,程序将直接退出,任何对象的析构函数都不会调用
异常机制
对异常的处理有三个组成部分:
引发异常 捕获处理程序的异常 使用try
堆栈解退
当抛出了异常,但还没在特定的作用域中被捕获时,函数调用堆栈便被“解退”,并试图在下一个外层try…catch代码中捕获这个异常。解退函数调用堆栈意味着抛出未捕获异常的那个函数将终止,这个函数中的所有局部变量都将销毁,控制会返回到原先调用这个函数的语句。
如果有一个try代码块包含了这条语句,则它就会试图捕获这个异常。如果没有代码块包含这条语句,则堆栈解退再次发生。如果没有任何catch处理器捕获这个异常,则会调用terminate函数,终止程序。
下面的demo演示了堆栈解退:
运行结果:
注意:
程序运行堆栈解退以回到能够捕捉异常的地方时,将释放对战中的自动存储型变变量,如果变量是类对象, 将为该对象调用析构函数
其他类异常特性
try-catch 跟 函数的区别:
函数调用返回时将控制权返回给调用其的函数, 而try-catch结构将控制权向上级返回。
exception类
http://www.cnblogs.com/uniqueliu/archive/2011/08/01/2124261.html
object.func().func2(); class A { //... }; class B { //... A a; A b; }; #include <iostream> using namespace std; class A { public: A(int i){x=i;cout<<"调用A类的构造函数\n";} ~A(){cout<<"调用A类的析构函数\n";}; void get() {cout<<"A类中X的值为:"<<x<<endl;} private: int x; }; class B { public: B(int i,int j,int k):a(i),b(j),y(k){cout<<"调用B类的构造函数\n";} A geta(){return a;} A getb(){return b;} ~B(){cout<<"调用B类的析构函数\n";} void gety(){cout<<"B类中y的值为:"<<y<<endl;} private: A a; A b; int y; }; int main() { B b(1,2,3); b.geta().get(); b.getb().get(); b.gety(); return 0; }
友元类
如果某类B的成员函数会频繁的存取另一个类A的数据成员, 而A的数据成员的Private/Protectd限制造成B存取的麻烦, B只能通过A的Public的成员函数进行间接存取
把B做成A类的友元类,即A类向B类开放其Private/Protectd内容, 让B直接存取
友元类:一个类可以作另一个类的友元
友元类的所有成员函数都是另一个类的友元函数
友元类的声明:
friend class 类名;
友元类注意事项:
1、友元关系是单向的
2、友元关系不能被传递
3、友元关系不能被继承
4、有时候需要注意前向声明
#ifndef _TELE_CONTROLLER_H_ #define _TELE_CONTROLLER_H_ class Television; class TeleController { public: void VolumeUp(Television &tv); void VolumeDown(Television &tv); void ChanelUp(Television &tv); void ChanelDown(Television &tv); }; #endif // _TELE_CONTROLLER_H_
#include "TeleController.h" #include "Television.h" void TeleController::VolumeUp(Television &tv) { tv.volume_ += 1; } void TeleController::VolumeDown(Television &tv) { tv.volume_ -= 1; } void TeleController::ChanelUp(Television &tv) { tv.chanel_ += 1; } void TeleController::ChanelDown(Television &tv) { tv.volume_ -= 1; }
#ifndef _TELEVISION_H_ #define _TELEVISION_H_ class TeleController; class Television { friend class TeleController; public: Television(int volume, int chanel); private: int volume_; int chanel_; }; #endif // _TELEVISION_H_
#include "Television.h" Television::Television(int volume, int chanel) : volume_(volume), chanel_(chanel) { } #include "Television.h" #include "TeleController.h" #include <iostream> using namespace std; int main(void) { Television tv(1, 1); TeleController tc; tc.VolumeUp(tv); return 0; }
嵌套类,局部类:
局部类
局部类是指在函数中定义类。
(c++不能在函数中定义函数。c++在类中定义的函数也就是成员函数。)这个类以及由它创建的对象,都局限在该函数作用域中;必须在类内实现所有的成员函数,不能拿到类外。因为函数是不可以嵌套定义的;若类内含有静态数据成员,必须在该函数外初始化;类内不可含有静态函数成员;类中不可使用包裹它的函数所定义的除静态外的局部变量。
局部类
int a; void fun() { static int s; class A { public: void init(int i) { s = i; } }; A m; m.init(10); }
局部类的另一个用途是用来实现类型转化
class Interface { public: virtual void Fun() = 0; }; template <class T, class P> Interface* MakeAdapter(const T& obj, const P& arg) { int x; class Local : public Interface { public: Local(const T& obj, const P& arg) : obj_(obj), arg_(arg) {} virtual void Fun() { x = 100; obj_.Call(arg_); } private: T obj_; P arg_; }; return new Local(obj, arg); }
.内嵌类
是在类体内定义的又一个类。外面的类叫外围类。这个类以及由它创建的对象,都局限在外层类作用域中;
外界能否使用内层类,全在于访问权限;若能使用,定要以外围类::内层类格式来用;
是类组合演化的又一种类间关系,即组合或聚集成员不是产生于其它类,而是产生于内层类;内层类的成员函数,可以在类内实现,也可以在外层类之外实现;
内层类的成员函数对外围类的成员没有访问权,反之亦然
定义嵌套类的目的在于隐藏类名,减少全局的标识符,从而限制用户能否使用该类建立对象。这样可以提高类的抽象能力,并且强调了两个类(外围类和嵌套类)之间的主从关系。
class A { public: class B { public: … private: … }; void f(); private: int a; }
其中,类B是一个嵌套类,类A是外围类,类B定义在类A的类体内。
2 对嵌套类的若干说明:
1、从作用域的角度看,嵌套类被隐藏在外围类之中,该类名只能在外围类中使用。如果在外围类的作用域内使用该类名时,需要加名字限定。
2、从访问权限的角度来看,嵌套类名与它的外围类的对象成员名具有相同的访问权限规则。不能访问嵌套类的对象中的私有成员函数,也不能对外围类的私有部分中的嵌套类建立对象。
3、嵌套类中的成员函数可以在它的类体外定义。
4、嵌套类中说明的成员不是外围类中对象的成员,反之亦然。嵌套类的成员函数对外围类的成员没有访问权,反之亦然。国此,在分析嵌套类与外围类的成员访问关系时,往往把嵌套类看作非嵌套类来处理。
异常
abort
于一个用C++写的程序,被加载至内存后运行,最终走向死亡。程序的死亡大致有三种:自然死亡,即无疾而终,通常就是main()中的一个return 0;自杀,当程序发现自己再活下去已经没有任何意义时,通常会选择自杀。当然,这种自杀也是一种请求式的自杀,即请求OS将自己毙掉。有两种方式:void exit(int status)和void abort(void)。他杀,同现实不同的是,程序家族中的他杀行径往往是由自己至亲完成的,通常这个至亲就是他的生身父亲(还是母亲?)。C++并没有提供他杀的凶器,这些凶器往往是由OS直接或者间接(通过一些进程库,如pthread)提供的。 自然死是最完美的结局,他杀是我们最不愿意看到的,自杀虽是迫不得已,但主动权毕竟还是由程序自己掌控的;abort被调用时,程序将直接退出,任何对象的析构函数都不会调用
#include <iostream> #include <string.h> #include <stdio.h> #include <cstdlib> using namespace std; struct node { double y; node(){ cout<<"new"<<endl; } ~node(){ cout<<"delete -- "<<y<<endl; } }; double hmean(node a, node b){ if(a.y == -b.y){ std::abort(); } return 2.0*a.y*b.y/(a.y + b.y); } int main(){ node a, b, c; while(scanf("%lf %lf", &a.y, &b.y)){ c.y = hmean(a, b); printf("%lf\n",c.y); } return 0; }
异常机制
对异常的处理有三个组成部分:
引发异常 捕获处理程序的异常 使用try
#include <iostream> #include <stdio.h> #include <algorithm> using namespace std; double hmean(double a, double b); int main(){ double x, y, z; printf("Enter two numbers :"); while(scanf("%lf %lf", &x, &y) != EOF){ try{ z = hmean(x, y); } catch(const char *s){ printf("%s",s); continue; } printf("%f %f", x, y); printf(" %f \n",z); } printf("BYE\n"); return 0; } double hmean(double a, double b){ if(a == -b) throw "bad hmean() arguments : a = -b not allowed"; return 2.0 * a * b/(a + b); }
堆栈解退
当抛出了异常,但还没在特定的作用域中被捕获时,函数调用堆栈便被“解退”,并试图在下一个外层try…catch代码中捕获这个异常。解退函数调用堆栈意味着抛出未捕获异常的那个函数将终止,这个函数中的所有局部变量都将销毁,控制会返回到原先调用这个函数的语句。
如果有一个try代码块包含了这条语句,则它就会试图捕获这个异常。如果没有代码块包含这条语句,则堆栈解退再次发生。如果没有任何catch处理器捕获这个异常,则会调用terminate函数,终止程序。
下面的demo演示了堆栈解退:
#include <iostream> #include <stdexcept> using namespace std; void fun3() throw (runtime_error) { cout<<"In fun 3"<<endl; throw runtime_error("runtime_error in fun3"); } void fun2() throw (runtime_error) { cout<<"fun3 is called inside fun2"<<endl; fun3(); } void fun1() throw (runtime_error) { cout<<"fun2 is called inside fun1"<<endl; fun2(); } int _tmain(int argc, _TCHAR* argv[]) { try { cout<<"fun1 is called inside main"<<endl; fun1(); } catch(runtime_error &error) { cout<<"Exception occurred: "<< error.what()<<endl; cout<<"exception handled in main"<<endl; } system("pause"); return 0; }
运行结果:
注意:
程序运行堆栈解退以回到能够捕捉异常的地方时,将释放对战中的自动存储型变变量,如果变量是类对象, 将为该对象调用析构函数
其他类异常特性
try-catch 跟 函数的区别:
函数调用返回时将控制权返回给调用其的函数, 而try-catch结构将控制权向上级返回。
exception类
相关文章推荐
- c++删除文件
- C++实现红黑树建立,销毁,查找,插入和删除
- C++实现哈希表的创建,销毁,键值插入与删除
- C++builder 数据库常用操作
- 个人学习c++的真实经验
- C/C++中位运算杂谈
- [C/Cpp/Java]编程语言的一些通用概念
- c语言:编写一个简易计算器,打印菜单界面,实现加减乘除运算,可以退出菜单界面
- c语言:从键盘输入BOY三个字符,然后把它们输出到屏幕。
- c语言:先后输出BOY三个字符
- c语言:用%f输出实数,只能得到6位小数及求float型数据的有效位数
- c语言:求一元二次方程的跟,系数a,b,c由键盘输入(要求考虑所有情况)
- c语言:任给三条边长,判断能否构成三角形,如果能,求出其面积和周长
- c语言:两种方法实现给定一个大写字母,用小写字母输出
- c语言:获取一个数二进制序列中所有的偶数位和奇数位,分别输出二进制序列。
- c语言:将数组A中的内容和数组B中的内容进行交换。(数组一样大)
- c++11 单例模式
- C++学习笔记2
- 嵌入式寄存器操作-----C语言位操作的学习
- C语言URL编解码