c++11学习笔记(2)


(1)一个const成员函数如果以引用的形式返回*this,那么它返回类型将是常量引用。(2)通过区分成员函数是否是const,可以对其进行重载。因为非常量版本的函数对于常量对象是不可用的,所以我们只能在一个常量对象上调用const成员函数。
下面的例子中,定义一个名为do_display的私有成员,由它负责打印screen的实际工作,所有的display操作都将调用这个函数,然后返回执行操作的对象。

复制代码
class Screen{
public:
  Screen &display(ostream &os )
  {
    do_display(os);
    return *this;
  }
  const Screen &display(ostream &os) const
   {
  }
private:
  void do_display(ostream &os) const
  {
    os << contents;
  }
}
复制代码

当display调用do_display的时候,它的this指针隐式传递给do_display,而当display的非常量版本调用do_display,它的this指针将隐式地从指向非常量的指针转换成指向常量的指针。
(3)之前的类把三个普通的非成员函数定义成了友元。类还可以把其他的类定义成友元,也可以把其他类的成员函数定义成友元。此外,友元函数能定义在类的内部,这样的函数是隐式的。
(4)友元关系不存在传递性,也就是说,如果window_mgr有它自己的友元,则这些友元并不能理所当然地具有访问screen的特权。

class Screen
{
  friend class window_mgr;
}

(5)除了另整个类作为友元之外,screen还可以只为某个成员函数提供访问权限。当把一个成员函数声明成友元的时候,我们必须明确指出该成员函数属于哪个类。

class screen
{
    friend void window_mgr::clear(screenindex);
}

(6)如果想要另某个成员函数作为友元,我们必须仔细组织程序的结构以满足声明和定义的彼此依赖关系。必须按照以下方式设计程序。
首先定义window_mgr类,其中声明clear函数,但是不能定义它。接下来定义screen,包括对于clear的友元声明。最后定义clear,此时它才可以使用screen的成员。
(7)尽管重载函数的名字相同,但是他们仍然是不同的函数。因此,如果一个类想把一组重载函数声明成它的友元,它需要对这组函数中的每一个分别声明。

复制代码
extern ostream& storeon(ostream &, screen &);
extern bitmap& storeon(bitmap &, screen &);
class screen
{
  friend ostream& storeon(ostream &, screen &);
}
复制代码

(8)如果没有在构造函数的初始值列表中显式的初始化成员,则该成员将在构造函数体之前执行默认初始化。

复制代码
sales_data::sales_data(const string &s, unsigned cnt, double price)
{
    bookno=s;
    units_sold=cnt;
    revenue=cnt*price;
}
复制代码

这段代码和我们之前原始定义的效果是相同的,当构造函数完成以后,数据成员的值相同。区别是原来的版本初始化了它的数据成员,而这个版本是对数据成员执行了赋值操作。这个区别到底会有什么深层次的影响完全依赖于数据成员的类型。(const和引用)
(9)如果成员是const或者引用的时候,必须将其进行初始化而不是赋值。类似的,当成员属于某种类类型且该类没有定义默认构造函数的时候,也必须将这个成员初始化。

复制代码
class Constref
{
  public:
  Constref(int i);
  private:
  int i;
  const int ci;
  int & ri;
}
复制代码

和其他常量对象或者引用一样,成员ci和ri都必须被初始化。因此,如果我们没有为他们提供构造函数初始值的话将引发错误。
//这个是完全不对的

复制代码
Constref::Constref(int ii)
{
  i=ii;
  ci=ii;
  ri=i;
}
复制代码

//下面这个才是对的

Constref::Constref(int ii): i(ii), ci(ii), ri(i)

(10)成员的初始化顺序和它们在类定义中的出现顺序一致,第一个成员先被初始化,然后第二个,以此类推。构造函数初始值列表中初始值的前后位置关系不会影响实际的初始化顺序。一般来说,初始化的顺序没什么特别要求。不过如果一个成员使用另一个成员来初始化,那么这两个成员的初始化顺物就很关键。
(11)c++11新标准扩展了构造函数初始值的功能,使得我们可以定义所谓的委托构造函数(delegating constructor)。一个委托构造函数使用它所属类的其他构造函数执行它自己的初始化过程,或者说把它自己的一些职业全部委托给其他的构造函数。

复制代码
class sales_data
{
public:
  sales_data(string s, unsigned cnt, double price): bookno(s), units_sold(cnt), revenue(cnt*price) { }
  //其余构造函数全都委托给另一个构造函数
  sales_data(): sales_data("", 0, 0) { }
}
复制代码

(12)对于c++新手来说有一种常犯的错,试图用以下的形式声明一个用默认构造函数初始化的对象。

sales_data obj( );//错误,声明了一个函数而非对象
sales_data obj;

(13)

sales_data& sales_data:: combine(const sales_data & rhs)
string null_book = "999";
item.combine(null_book);

这里用一个string实参点用了sales_data的combine成员,该调用是合法的,编译器用给定的string自动创建了一个sales_data 对象。新生成的这个临时对象被传递给combine。因为combine的参数是一个常量引用,所以我们可以给该参数传递一个临时量。

posted @   花与不易  阅读(95)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示