关于move、friend的使用和隐式转换,面向对象(基于C++)笔记5.5

•A friend class must be previously declared in an enclosing scope or defined in the non-class scope immediately enclosing the class that is declaring it a friend
 class X { … };
 namespace N {
  class Y {
     friend class X;
     friend class Z;
     friend class AE;
  };
  class Z { … };
 }

 class AE { … }; // not a friend of Y


友元函数可以像友元一样声明,也可以通过其自定义参数的作用域找到。

例子:

 namespace N{

   class X;

   void f();

   void h(const X&);

   class X {

       friend void f();

       friend void h(const X&);

   };

 }

 void g(const N::X& x)

 {    f(); // ERROR

      h(x);//CORRECT

 }


什么时候用友元?什么时候用成员?

面向对象设计的特点应该是封装性,我们需要思考这个函数是否需要访问私有数据成员?如果确实需要访问,还涉及成员状态的属性,我们就需要友元函数。

某些操作必须是成员函数: 构造函数、析构函数、= 、 [ ] 、 ( ) 、 ->

修改类状态的操作应该是成员函数或采用非 const 引用(或指针)参数的全局函数。


隐式类型转换

先给例子:

 class X {

    …

public:

    X(int);

    int m1();

    int m2() const;

    friend int f1(X&);

    friend int f2(const X&);

    friend int f3(X);

 };

 99.m1() or 99.m2()   //error

 f1(99)   //error

 f2(99) and f3(99)   //OK

为什么99.m1()是错的?是因为点运算符和指针的指向运算分左侧的对象是不会帮你做隐式类型转换的。

f1(99)错误的原因在于f1(x&)的参数是引用类型,只能引用左值,所以不能引用临时对象,想要引用临时对象只能通过const &,f3的参数是X,99就会调用构造函数,创建临时对象。

If implicit conversion is desired for all operands of an operation,  the function implementing it must be a nonmember function taking a constant reference parameter or a non-reference parameter.
If no conversions are defined,  both OK.

我们都知道,运算符函数参数的数据类型用指针就不合适,效率慢。

当我们用用临时对象返回,涉及到拷贝操作,会比较耗时。为了提高效率,我们就会采用move。

move的操作其实就是接管临时对象的存储空间(转移控制权),这样就不需要创建另外的存储空间。

 &&是右值引用,为什么右值引用不能加const,因为在move constructor和assignment中会修改这个对象的状态(原来的对象的指针会修改指向NULL,让operator接管原来的空间)

//move版本 
 void swap(matrix& a, matrix& b)
  { matrix t{move(a)};
    a=move(b); 
    b=move(t);
  }

//copy版本
void swap(matrix& a, matrix& b)
  { matrix t;
    t=a;
    a=b;
    b=t;
  }
 string g(string arg)
 {
    return arg;
 }
 string s{"Newton"};
 s=g(s);
/* string arg=s; string temp=arg;
   destroy arg;
   s=temp; destroy temp. */

上面是实参初始化临参的例子,内部的操作中包含了建立了一个temp拷贝了返回的arg,当s被赋值完后就会destroy temp。(注意释放的先后顺序)


 这里的Mystring s=’a其实调用的是MyString(unsigned int=100);这就造成了隐式的混淆。

因此出现了关键词explicit,要求定义的函数为显式函数。

 class String{
 explicit String(int n);
 String(const char*);
  ……
 };
 String s1 = 'a'; // Error
 String s2(10); 
 String s3 = String(10); 
 String s4 = "xxxx";
 String s5("xxxx"); 

 比较条件可以是一个比较对象类,重载()符号。


重载++符号的注意事项

递增和递减运算符在C++运算符中是唯一的,因为它们可以用作前缀和后缀运算符。 后缀运算符需要一个 int 参数来将其与前缀运算符区分开来。 这个参数没有意义——所以叫假参数,它不能用在算子函数定义中。

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

NightHacker

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值