回 帖 发 新 帖 刷新版面

主题:类中运算符自定义/重载,和关于友元的问题

学校发的参考书太难看明白了~问问高手们先......[em12][em12]
这么小的问题也麻烦你们~不好意思了~谢谢拉~

今有一个链表类,有成员操作符'=',
'='在我写的Header里的声明:
friend LinkL &operator=(const LinkL &);
定义:
LinkL &LinkL::operator=(const LinkL &another)
{
    *cur_another=another.head;
    /////
}

编译时提示:
e:\microsoft visual studio\myprojects\newset(2)\newset\linklheader.h(21) : error C2801: “operator =”必须是非静态成员
LinkLDef.cpp
e:\microsoft visual studio\myprojects\newset(2)\newset\linklheader.h(21) : error C2801: “operator =”必须是非静态成员
e:\microsoft visual studio\myprojects\newset(2)\newset\linkldef.cpp(122) : error C2600: “LinkL::operator =”: 不能定义编译器生成的特殊成员函数(必须首先在类中声明)

那就是说这个操作符默认已经有定义了的?教材上说'='运算符是可以定义的哇~那么应该怎么用我自己的定义而不是编译器(visual studio2005)默认的定义?

另外~*cur_another=another.head这一句,head是我定义的LinkL类的私有成员,怎样才能在成员函数里访问同一个类另一个对象的私有成员?是不是象上面那样声明为友元就可以了的?

谢谢谢谢谢谢谢谢大家拉!

回复列表 (共13个回复)

沙发

赋值(=)、取址(&) 和序列 (,)已经有了预定义的意义——可将它们定义为private,从而使普通用户无法访问

这是参考书(<<C++程序设计语言>>,Bjarne Stroustrup)上的说法~ 什么意思? 那么我要用等号'='实现一个动态的链表的复制要怎样做?

板凳

其它的错误我不管,管个面向对象的严重错误!

既然一个函数是一个类的友元函数!那么这个函数只是这个类的朋友,不是这个类中的成员!但它还是可以访问类的私有成员,但必须加类或引用参数,因它没有this指针!记住:友元破坏了面向对象的封装机制,在不得己的情况最好少用!

定义:
LinkL&  operator=(const LinkL &another)
{
    *cur_another=another.head;
    /////
}

3 楼

这我就更不明白了~ 在上述著作中(Bjarne Stroustrup是贝尔实验室中C++的设计者和最早实现者),作者在第二部分"抽象机制"11.5节里的确用了例子来介绍友元,
原文如下(比较长~打得辛苦):
..... 为避免这些情况,我们可以声明这个operator*作为两个类的友元:
class Matrix;

class Vector{
     float v[4];
     //...
     friend Vector operator*(const Matrix&, const Vector&);
};

class Matrix{
     Vector v[4];
     //...
     friend Vector operator*(const Matrix&, const Vector&);
};

Vector operator*(const Matrix& m, const Vector&v){
     //以下是Matrix和Vector类进行矩阵乘法的算法,略
}

**************
我不打算认为作者介绍的方法会破坏面向对象的数据封装安全部分的准则.因为~我还是不明白~~

4 楼

噢补充~ 关于上面引用"为了避免这种情况",该情况指:
'*'被定义为做Matrix和Vector类间的矩阵乘法的运算,所以要同时访问两个类的私有成员,但又不希望要专门在两个类中都写上繁复的修改私有对象的成员函数(而且这样的代码写出来后不是很美观).

请指教 :D

5 楼

[quote]但它还是可以访问类的私有成员,但必须加类或引用参数,因它没有this指针!
[/quote]
琢磨了一会~这里有点明白了~ 你的意思是:这个friend LinkL &operator+(const LinkL&)是没有this指针的?
那么假如我要操作加号左边和右边两个都是LinkL类的参数,应该怎么声明?
friend不能位于类定义之外.编译器说的.
是不是说我应该把它声明如下:
LinkL &operator =(LinkL &left,const LinkL &right);
???[em1][em1]

6 楼

MSDN中说Static member functions do not have a this pointer
然后顶楼有错误提示说“operator =”必须是非静态成员
到底operator=能不能是友元该怎样用? 我混乱啊混乱啊
晕了` 似乎大家都睡觉去了......没人帮我了~~` 晕了晕了~

7 楼

=操作符重载函数不能为友元函数,只能为某类中的成员函数!你还是去掉友元(friend)吧!
[em9]

8 楼

我的大哥啊:
   一元运算符重载函数只能有一个参数,二元运算符重载函数才能有两个参数!你首先把那些是一元运算符,那些是二元运算符搞明白先!!!
如果说一元运算符重载为类成员函数,不能够有参数,因它己有个this参数,二元运算符重载为类成员函数,可以有一个参数!

9 楼

8楼这点我明白~不过因为之前你说因为友元没有this指针.而且根据书里的例子推测,(友元'*'二元运算符重载那里用了2个参数).所以我认为operator=参数表里需要2个参数了~ 嗯~ 不是这样的吗???

然后关于'='的重载.我大概可能搞明白了...应该是因为在类里'='号是有默认的定义的,编译器默认的定义是调用类的拷贝构造函数(LinkL(const LinkL &)).所以我自己定义一个使用相同参数的'='操作符运算时就重定义/重载无法区分调用哪个函数出错了.

所以目前我只有一点不明白的了~ 友元操作符定义时(二元为例)要多少个参数?

不好意思啊~ 因为毕竟在论坛里讨论问题不能完全地系统,所以我理解的和你说的可能有出入~ 劳烦了~  :P

10 楼

[quote]8楼这点我明白~不过因为之前你说因为友元没有this指针.而且根据书里的例子推测,(友元'*'二元运算符重载那里用了2个参数).所以我认为operator=参数表里需要2个参数了~ 嗯~ 不是这样的吗???

然后关于'='的重载.我大概可能搞明白了...应该是因为在类里'='号是有默认的定义的,编译器默认的定义是调用类的拷贝构造函数(LinkL(const LinkL &)).所以我自己定义一个使用相同参数的'='操作符运算时就重定义/重载无法区分调用哪个函数出错了.

所以目前我只有一点不明白的了~ 友元操作符定义时(二元为例)要多少个参数?

不好意思啊~ 因为毕竟在论坛里讨论问题不能完全地系统,所以我理解的和你说的可能有出入~ 劳烦了~  :P[/quote]


你理解得完全正确!只是~运算符是一元运算符,如果是类运算符函数不能有参数,如果为友元重载函数只能有一个参数!
我为何说你完全正确!因为赋值运算符都是二元运算符,在类中定义可有一个参数,定义为友元重载函数可以有两个参数,但它为何不能定义为类友元重载函数,楼主看的是C++之父(C++设计者)的书,我想它应该告诉你了吧!我也谈谈我的个人看法,但愿对有些朋友一些帮助:
  赋值运算符都只能定义为类运算符,虽然它是个二元运算符,但不能定义为友元运算符。假如将赋值运算符重载为Dog类的友元:
    friend Dog operator=( Dog &d1, Dog &d2)
   {
       d1.age =  d2.age;
       return d1;
    }
例如有表达式 x = y;可以正确的将y赋值给x; x,y都是Dog类的对象。
又例如有一表达式99 = y;它被解释为operator=(99, y);
C++编译器将99转换为一个Dog类的对象(隐含的临时变量),然后使形参引用对象,因此这是个正确的表达式。但按C++的规定(99=y常量怎能赋值),这样的表达式应是错误的,为了保证与C++规定的赋值语义相一致,应将赋值运算符重载为类运算符。同样,也应将+=,-=等这些赋值运算符重载为类运算符!

(附加: 我只有上班才能回答你的问题(嘘,小心boss炒我鱿鱼啊),下班后我有我的自由空间!)

我来回复

您尚未登录,请登录后再回复。点此登录或注册