正文

运输法虚重载2008-11-03 21:47:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/vfdff/39220.html

分享到:

你这儿是没有办法把<<申明为virtual,因为作为成员函数   
  <<只能是ostream的member。   
  不过换一种方法还是可以的   
  大致如下哈:   
    
  class   FtpMessage   {   
  protected:   
      virtual   void   ToString(ostream   &os)   =   0;   
  public:   
      ...   
      friend   ostream&   operator   <<(ostream&   os,   FtpMessage   &   msg);   
  };   
    
  ostream&   operator   <<(ostream&   os,   FtpMessage   &   msg)   
  {   
      msg.ToString(os);   
      return   os;   
  }   
    
  class   FtpCtrlMsgCtoS   :   public   FtpMessage   
  {   
  protected:   
      virtual   void   ToString(ostream   &os){   
            //specific   handling   for   FtpCtrlMsgCtoS     
      }   
  };   
    
  class   CtoSPORT   :   public   FtpCtrlMsgCtoS   
  {   
  protected:   
      virtual   void   ToString(ostream   &os){   
            //specific   handling   for   CtoSPORT     
      }   
  }   
    
  namespace   std   
  {   
      template<>   
          class   ostream<FtpMessage>{   
          };   
  }   
    
  ...   
  void   FtpDaemon::SendFtpCtrlMsgCtoS(FtpCtrlMsgCtoS&   msg)   
  {   
          ostringstream   os;   
          os   <<   msg;   
          send(socketFtpCtrl,   os.str().c_str(),   os.str().length()+1,   0);   
  }   


说明:有的C++编译系统没有完全实现C++标准,它所提供不带后缀.h的头文件不支持把成员函数重载为友元函数。

简单说明一下吧:
#include <iostream>
using namespace std;

class A
{
public:
A operator *(A & a)
{
return a;
}
int value;
};

int main()
{
A * test_a=new A;
test_a->value=2;
cout<<(* test_a).value<<endl;
return 0;
}

流操作符 < <和>>重载返回值为引用,这两个操作符常常希望被连续使用,例如:cout < < "hello" < < endl; 因此这两个操作符的返回值应该是一个仍然支持这两个操作符的流引用。可选的其它方案包括:返回一个流对象和返回一个流对象指针。但是对于返回一个流对象,程序必须重新(拷贝)构造一个新的流对象,也就是说,连续的两个 < <操作符实际上是针对不同对象的!这无法让人接受。对于返回一个流指针则不能连续使用 < <操作符。因此,返回一个流对象引用是惟一选择。这个唯一选择很关键,它说明了引用的重要性以及无可替代性,也许这就是C++语言中引入引用这个概念的原因吧。 赋值操作符=。这个操作符象流操作符一样,是可以连续使用的,例如:x = j = 10;或者(x=10)=100;赋值操作符的返回值必须是一个左值,以便可以被继续赋值。因此引用成了这个操作符的惟一返回值选择。。

而+-*/ 四则运算符。它们不能返回引用,主要原因是这四个操作符没有side effect,因此,它们必须构造一个对象作为返回值,可选的方案包括:返回一个对象、返回一个局部变量的引用,返回一个new分配的对象的引用、返回一个静态对象引用。根据前面提到的引用作为返回值的三个规则,第2、3两个方案都被否决了。静态对象的引用又因为((a+b) == (c+d))会永远为true而导致错误。所以可选的只剩下返回一个对象了。


对模板来说,友元函数有三种:
1.非模板友元类或者友元函数,这个没什么好说的,直接写就是了。
2.绑定的友元类或者友元函数。这个就是类模板和友元函数(类)之间的一对一的映射。
      声明形式就是:  
          template  <class  Type>
          class  classname{
            ...
              friend  int  func <Type> (param...);
          }            

3.非绑定的友元类或者友元函数。这个就是类模板和友元函数(类)之间的一对多的映射。
      声明形式就是:  
          template  <class  Type>
          class  classname{
            ...
            template  <class  T>
              friend  int  func(param...);
          }  



首先感谢大家的关注和回答.但是发现大家热心有余,认真不足-------因为没有一个人真的编译过我的问题代码..
我在帖子中给的问题代码,因为去除了所有其他的不相关代码,所以是可以编译通过的.如下:
/////////////// Matrix.h 文件内容 (部分代码)//////////////////
#include <iostream>
//// Matrix 模板前向声明 /////
template <typename T>
class Matrix;
/////////////////////////////
template <typename T>
std::ostream& operator * (std::ostream& os,const Matrix <T>& mat);///  编译通过

template <typename T>
std::ostream& operator < < (std::ostream& os,const Matrix <T>& mat);  ///  ///  编译通过


template <typename T>
class Matrix
{
friend std::ostream& operator * <T> (std::ostream&,const Matrix <T>&);    ///  编译 通过
friend std::ostream& operator < < <T> (std::ostream&,const Matrix <T>&);  ///  编译  通过  
};


而我之前之所以不能编译通过,是因为我的实际代码中声明 了 一个 operator * 的重载成员函数,
导致它和友元的operator * 模板函数冲突  (但实际不应该这样啊.没看见过C++有这类语法要求.)

真正编译不通过的代码如下:

/////////////// Matrix.h 文件内容 (这段代码编译不通过)//////////////////
#include <iostream>
//// Matrix 模板前向声明 /////
template <typename T>
class Matrix;
/////////////////////////////
template <typename T>
std::ostream& operator * (std::ostream& os,const Matrix <T>& mat);///  编译通过

template <typename T>
std::ostream& operator < < (std::ostream& os,const Matrix <T>& mat);  ///  ///  编译通过


template <typename T>
class Matrix
{
        const Matrix operator *(const Matrix&) const; ////////  注意..这里是问题的根源!!!!!!
friend std::ostream& operator * <T> (std::ostream&,const Matrix <T>&);    ///  编译不通过
friend std::ostream& operator < < <T> (std::ostream&,const Matrix <T>&);  ///  编译  通过  
};

昨天发现出现编译不通过的问题后,我被引入了误区,一直以为是operator * 的问题
甚至发现 operator +, operator -,operator / 都不可以.  
唯独 operator < < 可以.
后来我发现如果在类中也声明一个  operator < < 的重载成员函数,那么  
friend std::ostream& operator < < <T> (std::ostream&,const Matrix <T>&);
这一段也将编译不通过...

所以找到解决方案------ 把所有的friend 声明,都写在类的成员定义之前.代码如下:

/////////////// Matrix.h 文件内容 ( 编译 成功!yeah)//////////////////
#include <iostream>
//// Matrix 模板前向声明 /////
template <typename T>
class Matrix;
/////////////////////////////
template <typename T>
std::ostream& operator * (std::ostream& os,const Matrix <T>& mat);///  编译通过

template <typename T>
std::ostream& operator < < (std::ostream& os,const Matrix <T>& mat);  ///  ///  编译通过


template <typename T>
class Matrix
{
        //////注意,,把所有 friend 声明都放在成员定义之前..////////////
        friend std::ostream& operator * <T> (std::ostream&,const Matrix <T>&);    ///  编译 通过
friend std::ostream& operator < < <T> (std::ostream&,const Matrix <T>&);  ///  编译  通过  
        const Matrix operator *(const Matrix&) const; ////////  注意..这里是问题的根源!!!!!!
};


template<typename T>
class Matrix;

template <typename T>
std::ostream&  operator* (T,const Matrix<T>   &a);  

template   <typename T>   
class       Matrix   
{       
    friend       std::ostream&  operator* <>(T,const Matrix<T>   &a);   //////编译通过      
    friend       std::ostream&  operator  << <T> (T,const Matrix<T>   &a);   //////编译通过   
} ;  

初学的话给你说概念越说越迷糊,下面举例子来说,看代码:


-------------------------------------


#include <iostrem.h>

namespace myns {

class clsA {
protected:
static int m_ia;
public:
int m_ib;
public:
clsA():m_ib(0) {};
~clsA() {};
};

int clsA::m_ia=32; // 正确。m_ia是类clsA的静态变量,需要在类定义域外部初始化。

}

int myns::clsA::m_ia=32; // 同样正确,理由同上。但是m_ia只能初始化一次,因此本行与上一行仅能二者取其一。

void main()
{
myns::clsA c1; // 正确。类clsA定义在名字空间myns中,cl为clsA类型的变量。
cl.m_ib = 1; // 正确。点操作符用于引用类实例的成员。

using namespace myns;
clsA *pc1 = NULL; // 正确。先声明名字空间myns,然后可以直接声明其中定义的类的实例或指向他们的指针。
pc1 = &c1; // 取c1的地址赋值给pc1。
pc1->m_ib = 2; // 正确。箭头操作符用于引用指针对象的成员。

cout << c1.m_ib; // 输出2。

cout << c1.m_ia; // 错误,不能引用类中的保护成员。
cout << c1->m_ib; // 错误。箭头操作符不能引用非指针对象的成员。
cout << pc1.m_ib; // 错误。点操作符不能引用指针对象的成员。

}

阅读(4130) | 评论(1)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

loading...
您需要登录后才能评论,请 登录 或者 注册