您的位置:首页 > 编程语言 > C语言/C++

C++ 学习(友元, 异常, 其他)

2015-12-01 09:48 274 查看
包含:

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类
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: