C++ Primer 类 12.3-12.5 作用域,construtor,friend

原创 2016年05月31日 10:03:48

12.3 类作用域

1.在定义于类外部的成员函数中,形参表和成员函数体都出现在成员名之后。这些都是在类作用域中定义,所以可以不用限定而引用其他成员。例如,类 Screen中 get 的二形参版本的定义:

 

     char Screen::get(index r, index c) const
     {
         index row = r * width;      // compute the row location
 
         return contents[row + c];   // offset by c to fetch specified character
     }

该函数用 Screen 内定义的 index 类型来指定其形参类型。因为形参表是在 Screen 类的作用域内,所以不必指明我们想要的是 Screen::index。我们想要的是定义在当前类作用域中的,这是隐含的。同样,使用 index、width 和 contents 时指的都是 Screen 类中声明的名字。

2.函数返回类型不一定在类作用域中。必须用完全限定的类型名 Screen::index 来指定所需要的 index 是在类 Screen 中定义的名字。

3.类作用域中的名字查找 。(看书,最好的办法是取不同的名字)

12.4 构造函数

※构造函数是特殊的成员函数。在类对象定义时被调用。 不能通过定义的类对象调用构造函数,构造函数可以定义多个或者说构造函数允许重载。

※如果没有定义任何构造函数,系统就会给类分配一个无参的默认构造函数,类只要定义了一个构造函数,编译器也不会再生成默认构造函数。只有当一个类没有定义构造函数时,编译器才会自动生成一个默认构造函数.

※定义类对象时不能写成 Sales_item myobj(); 编译器会理解成:一个返回 Sales_item 类型叫 myobj的函数声明。 正确写法是去掉后面的括号。

※构造函数后面不允许定义成 const,这样定义会产生语法错误: Sales_item() const {};

※构造函数在执行时会做类数据成员的初始化工作。从概念上讲,可以认为构造函数分两个阶段执行:(1)初始化阶段;(2)普通的计算阶段。计算阶段由构造函数函数体中的所有语句组成。

※不管成员是否在构造函数初始化列表中显式初始化,类类型的数据成员(比如string)总是在初始化阶段初始化。初始化发生在计算阶段开始之前。

※使用构造函数初始化列表的版本初始化数据成员,没有定义初始化列表的构造函数版本在构造函数函数体中对数据成员赋值。

※记住,可以初始化 const 对象或引用类型的对象,但不能对它们赋值。在开始执行构造函数的函数体之前,要完成初始化。初始化 const 或引用类型数据成员的唯一机会是构造函数初始化列表中。

※构造函数初始化列表仅指定用于初始化成员的值,并不指定这些初始化执行的次序。成员被初始化的次序就是定义成员的次序

※具有默认实参的构造函数都会被编译器认为是默认构造函数,而默认构造函数只能有一个。

※http://write.blog.csdn.net/postedit/51541387

    ※下面的陈述中哪个是不正确的(如果有的话)?为什么?

    (a)类必须提供至少一个构造函数。

    (b)默认构造函数的形参列表中没有形参。

    (c)如果一个类没有有意义的默认值,则该类不应该提供默认构造函数。

    (d)如果一个类没有定义默认构造函数。则编译器会自动生成一个,同时将每个数据成员初始化

为相关类型的默认值。

【解答】

    (a)不正确。因为类也可以不提供构造函数,这时使用由编译器合成的默认构造函数。

    (b) 不正确。因为为所有形参都提供了默认实参的构造函数也定义了默认构造函数,而这样的构造函数形参列表中是有形参的。

    (c)不正确。囚为如果一个类没有默认构造函数(指的是该类提供了构造函数,但没有提供自己的默认构造函数),则在编译器需要隐式使用默认构造函数的环境中,该类就不能使用,所以,如果一个类定义了其他构造函数,则通常也应该提供1个默认构造函数(见12.4.3节)。

    (d)不正确。因为编译器合成的默认构造函数,不是将侮个数据成员初始化为相关类型的默认值,而是使用与变量初始化相同的规则宋初始化成员:类类型的成员执行各自的默认构造函数进行初始化;内置和复合类型的成员,只对定义在全局作用域中的对象才初始化(见12.4.3节)。

    ※默认情况下可以用单个实参来调用的构造函数定义了从形参类型到该类类型的一个隐式转换。

class mycls
{
    public:
        int i;

        mycls(int i){ };
 
        explicit mycls(string s){ };

};


mycls obj(2) ; 也可以这样使用这个构造函数 mycls obj = 2; 这里做了一个类型转换,但是这样的写法很不直观。

可以通过将构造函数声明为 explicit,来防止在需要隐式转换的上下文中使用构造函数:mycls obj("tom"), 无法用 mycls obj = "tom" 因为转换被禁止,通常,除非有明显的理由想要定义隐式转换,否则,单形参构造函数应该为 explicit。     

※explicit 关键字只能用于类内部的构造函数声明上。在类的定义体外部所做的定义上不再重复它。

12.5 友元

    ※在需要允许某些特定的非成员函数访问一个类的私有成员〔及受保护成贝)。而同时仍阻止一般的访问的情况下,友元是有用的。

    ※使用友元的优点:可以灵活地实现需要访问若干类的私有或受保护成员才能完成的任务;便于与其他不支持类概念的语言〔如C语言、汇编语言等)进行混合编程:通过使旧友元函数重载可以更自然地使用C一语言的I/O流库。

    ※使用友元的缺点:,个类将对其非公有成员的访问权授子其他的函数或类,会破坏该类的封装性,降低该类的可靠性和可维护性。

※友元的关系是单向的而不是双向的。如果声明了 B类是A类的友元类,不等于A类是B类的友元类,A类中的成员函数不能访问B类中的私有数据。

※友元的关系不能传递,如果B类是A类的友元类,C类是B类的友元类,不等于 C类是A类的友元类。

#include <iostream>
using namespace std;
 
class Bezaa; //Forward declaration of class Bezaa in order for example to compile.
class Aazaa
{
private:
    int a;
public:
    Aazaa() { a = 0; }
    void show(Aazaa& x, Bezaa& y);
    friend void show(Aazaa& x, Bezaa& y);// declaration of global friend
};
 
class Bezaa
{
private:
    int b;
public:
 
    Bezaa() { b = 6; }
    friend void show(Aazaa& x, Bezaa& y);// declaration of global friend
    friend void Aazaa::show(Aazaa& x, Bezaa&y); // declaration of friend from other class
};
 
// Definition of amember function of Aazaa; this member is a friend of Bezaa
void Aazaa::show(Aazaa&x, Bezaa& y)
{
  cout << "Show via function memberof Aazaa" << endl;
  cout << "Aazaa::a = "<< x.a << endl;
  cout << "Bezaa::b = "<< y.b << endl;
}
 
// Friend for Aazaaand Bezaa, definition of global function
void show(Aazaa& x,Bezaa& y)
{
  cout << "Show via globalfunction" << endl;
  cout << "Aazaa::a = "<< x.a << endl;
  cout << "Bezaa::b = "<< y.b << endl;
}
 
int main()
{
   Aazaa a;
   Bezaa b;
 
   show(a,b);
   a.show(a,b);
   system("pause");
}


输出结果为:

 

 

版权声明:本文为博主原创文章,未经博主允许不得转载。

C++12.3 类作用域(上)----需不需要加类作用域运算符 (类名: :)

简介==================================================================================================...

C++12.3 (下) 类作用域中名字查找(局部和全局)

参考 ** 12.3 (上 ) 类作用域 12.1.3成员函数重载和Screen类定义 ========================================================...

【足迹C++primer】18、类的作用域

类的作用域 每个类都会定义自己的作用域。 Screen::pos ht=24,wd=80; //使用Screen定义的pos类型 Screen scr(ht, wd,...

c++primer 3/7--类作用域,隐含的 this 指针

一般的数据或函数成员必须通过对象来访问。定义类型的成员,如 Screen::index,使用作用域操作符来访问。类使用作用域操作符(::) class Screen { public:...
  • G_rrrr
  • G_rrrr
  • 2012年03月07日 16:57
  • 638

C++ Primer笔记3_默认实参_类初探_名字查找与类的作用域

1.默认函数实参 在C++中,可以为参数指定默认值,C语言是不支持默认参数的,Java也不支持! 默认参数的语法与使用: (1)在函数声明或定义时,直接对参数赋值。这就是默认参数; (2)在函数...

C++primer学习:面象对象程序设计(4):继承类中的作用域和拷贝控制

派生类的作用域嵌套在基类之中.在编译时进行的名字查找是由静态类型决定的.关键概念:在进行函数调用时,假设我们使用p->mem(),则执行以下四个步骤.首先确定p对应的静态类型,查找对应的mem,如果找...

【C++ Primer Plus 9.2】 存储持续性、作用域和链接性

9.2 存储持续性、作用域和链接性(C++存储数据的方案)了解:C++存储数据的方案;9.2.1 存储持续性、作用域、链接不同的C++存储方式是通过存储持续性、作用域和链接性描述的。 1. 存储持...
  • vinater
  • vinater
  • 2015年06月13日 23:56
  • 483

虚函数和作用域(C++ primer 第五版)P550

一、程序 #include "stdafx.h" #include "iostream" using namespace std; class Base { public: virtual vo...

C++参数传递与作用域

  • 2011年07月18日 14:37
  • 1005KB
  • 下载

C++ 作用域规则

  • 2014年12月18日 11:38
  • 15KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C++ Primer 类 12.3-12.5 作用域,construtor,friend
举报原因:
原因补充:

(最多只允许输入30个字)