C++第五章数据的共享与保护练习题

习题来源: <<C++语言程序设计(第四版)>> 清华大学出版社 郑莉等编著
最后一次编辑时间: 2019-8-8

题目

5-1 什么是作用域? 有哪几种类型的作用域

5-2 什么叫做可见性? 可见性的一般规则是什么?

5-3 下面程序运行结果是什么?

#include<iostream>
using namespace std;
int x=5,y=7;
void myFunction()
{
    int y=10;
    coutc<"x from myFunction:"<<x<<"\n";
    oout<<"y from myPunetion:"<<y<"\n\n";
}


int main()
{
    cout<<"x from main:"<<x<<"\n";
    cout<<"y from main:"<<y<<"\n\n";
    myFunction ();
    cout<<"Back from myFunction!\n\n";
    cout<<"x from main;"<<x<<"\n":
    cout<<"y from main:"<<y<<"\n";
    return 0;
}

5-4 假设有两个无关系的类Engine和Fuel,使用时,如何使Fuel成员访问Engine中的私有和保护的成员?

5-5 什么叫做静态数据成员?它有何特点?

5-6 什么叫做静态函数成员?它有何特点?

5-7 定义一个Cat类,拥有静态数据成员numOfCats,记录Cat的个体数目;静态成员函数getNumOfCats(),读取numOfCats.设计程序测试这个类,体会静态数据成员和静态成员函数的用法。

5-8 什么叫做友元函数?什么叫做友元类?

5-9 如果类A是类B的友元,类B是类C的友元,类D是类A的派生类,那么类B是类A的友元吗?类C是类A的友元吗?类D是类B的友元吗?

5-10 静态成员变量可以为私有的吗?声明一个私有的静态整型成员变量。

5-11 在一个文件中定义一个全局变量n,主函数main(),在另一个文件中定义函数fnl(),在main()中对n赋值,再调用fnl(),在fnl()中也对n赋值,显示n最后的值。

5-12 在函数fnl()中定义一个静态变量n,fnl()中对n的值加1,在主函数中,调用nl()十次,显示n的值。

5-13 定义类X,Y,Z,函数 h(X*),满足:类X有私有成员i,Y的成员函数 g(X*) 是X的友元函数,实现对X的成员i加1;类Z是类X的友元类,其成员函数 f(X*) 实现对X的成员i加5;函数 h(X*) 是X的友元函数,实现对X的成员i加10,在一个文件中定义和实现类,在另一个文件中实现main()函数。

5-14 定义Boat与Car两个类,二者都有weight属性,定义二者的一个友元函数getTotalWeight().计算二者的重量和。

5-15 在函数内部定义的普通局部变量和静态局部变量在功能上有何不同?计算机底层对这两类变量做了怎样的不同处理,导致了这种差异?

5-16 编译和连接这两个步骤的输人输出分别是什么类型的文件?两个步骤的任务有什么不同?
在以下几种情况下,在对程序进行编译、连接时是否会报错?会在哪个步骤报错?
(1) 定义了一个函数 void f(intx,inty),以f(1)的形式调用。
(2) 在源文件起始处声明了一个函数void f(intx),但未给出其定义,以f(1)的形式调用。
(3) 在源文件起始处声明了一个函数voidf(intx),但未给出其定义,也未对其进行调用。
(4) 在源文件a.cpp中定义了一个函数void f(intx),在源文件b.cpp中也定义了一个函数void f(intx),试图将两源文件编译后连接在一起。







解答

5-1 什么是作用域? 有哪几种类型的作用域
标识符的作用范围

  • 函数原型作用域
  • 块作用域
  • 类作用域
  • 文件作用域

5-2 什么叫做可见性? 可见性的一般规则是什么?
是否可以引用, 使用前需要定义或者声明, 内层可引用外层, 外层不能引用内层

5-3 下面程序运行结果是什么?

#include<iostream>
using namespace std;
int x=5,y=7;
void myFunction()
{
    int y=10;
    coutc<"x from myFunction:"<<x<<"\n";
    oout<<"y from myPunetion:"<<y<"\n\n";
}


int main()
{
    cout<<"x from main:"<<x<<"\n";
    cout<<"y from main:"<<y<<"\n\n";
    myFunction ();
    cout<<"Back from myFunction!\n\n";
    cout<<"x from main;"<<x<<"\n":
    cout<<"y from main:"<<y<<"\n";
    return 0;
}
5
7
5
10

5-4 假设有两个无关系的类Engine和Fuel,使用时,如何使Fuel成员访问Engine中的私有和保护的成员?
设置友元类

class Fuel;
class Engine {
private:
    int powerlevel;
public:
    Engine()
    {
        this->powerlevel = 0;
    }
    void engine_fn(Fuel &f)
    {
        // TODO
    }
};

class Fuel {
private:
    int powerlevel;
public:
    Fuel()
    {
        this->powerlevel = 0;
    }
    void fuel_fn(Engine &e)
    {
        // TODO
    }
};

5-5 什么叫做静态数据成员?它有何特点?
一种采用static关键字来声明的成员变量, 其属于类, 只有一份, 类的所有对象共同维护与使用

5-6 什么叫做静态函数成员?它有何特点?
使用static关键字声明的函数成员, 其属于整个类, 同一个类的所有对象共同维护与共享

  • 静态成员函数只能直接访问同一个类的静态成员数据成员
  • 同一个类只维护一个静态成员函数

5-7 定义一个Cat类,拥有静态数据成员numOfCats,记录Cat的个体数目;静态成员函数getNumOfCats(),读取numOfCats.设计程序测试这个类,体会静态数据成员和静态成员函数的用法。

5-8 什么叫做友元函数?什么叫做友元类?

  • 前者是用friend关键字声明的函数, 可以访问相应类中的私有成员
  • 后者是用friend关键字声明的类, 它的所有成员函数都是相应类的友元函数

5-9 如果类A是类B的友元,类B是类C的友元,类D是类A的派生类,那么类B是类A的友元吗?类C是类A的友元吗?类D是类B的友元吗?

  • 不是, 不具有交换性
  • 不是, 不具有传递性
  • 不是, 不能被继承

5-10 静态成员变量可以为私有的吗?声明一个私有的静态整型成员变量。
可以

private:
    static int a;

5-11 在一个文件中定义一个全局变量n,主函数main(),在另一个文件中定义函数fnl(),在main()中对n赋值,再调用fnl(),在fnl()中也对n赋值,显示n最后的值。

fn1.main.h 文件

#include<iostream>
#include<stdlib.h>
# include"fn1.h"
using namespace std;

int n;

int main()
{
    n = 20;
    fn1();
    cout << "n的值为: " << n << endl;


    system("pause");
    return 0;
}

fn1.h 文件

#pragma once
extern int n;

void fn1()
{
    n = 30;
}

5-12 在函数fnl()中定义一个静态变量n,fnl()中对n的值加1,在主函数中,调用nl()十次,显示n的值。

#include<iostream>
#include<stdlib.h>

using namespace std;

void fn1()
{
    static int n = 0;
    n++;
    cout << "n的值为: " << n << endl;
}

int main()
{
    int i;
    for (i = 0; i < 10; i++)
    {
        fn1();
    }

    //1. 静态局部变量只在该函数内使用,不能在函数外使用,如果局部变量和全局变量名称相同,则全局变量在该函数体内被屏蔽
    //2. static变量只初始化一次
    //3. static修饰的全局变量,只能在该文件中使用
    system("pause");
    return 0;
}

输出结果

n的值为: 1
n的值为: 2
n的值为: 3
n的值为: 4
n的值为: 5
n的值为: 6
n的值为: 7
n的值为: 8
n的值为: 9
n的值为: 10

5-13 定义类X,Y,Z,函数 h(X*),满足:类X有私有成员i,Y的成员函数 g(X*) 是X的友元函数,实现对X的成员i加1;类Z是类X的友元类,其成员函数 f(X*) 实现对X的成员i加5;函数 h(X*) 是X的友元函数,实现对X的成员i加10,在一个文件中定义和实现类,在另一个文件中实现main()函数。

myheader.h 文件

#pragma once
#ifndef MYHEADER_H
#define MYHEADER_H

class X;
class Y {
public:
    void g(X* x);
};

class X {
private:
    int i;
public:
    X() :i(0) {}
    friend void h(X* x);
    friend void Y::g(X* x);
    friend class Z;
};

class Z {
public:
    void f(X* x)
    {
        x->i += 5;
    }
};

void h(X* x)
{
    x->i += 10;
}

void Y::g(X* x)
{
    x->i++;
}

#endif // !MYHEADER_H

main.c 文件

#include<iostream>
#include<stdlib.h>
#include"myheader.h"
using namespace std;



int main()
{
    X x;
    Y y;
    Z z;
    z.f(&x);
    h(&x);
    y.g(&x);

    system("pause");
    return 0;
}

5-14 定义Boat与Car两个类,二者都有weight属性,定义二者的一个友元函数getTotalWeight().计算二者的重量和。

#include<iostream>
#include<stdlib.h>

using namespace std;

class Car; // 向前声明
class Boat {
private:
    double weight;
public:
    Boat(int weight)
    {
        this->weight = weight;
    }
    friend double getTotalWeight(Boat &b, Car &c);
};

class Car {
private:
    double weight;
public:
    Car(int weight)
    {
        this->weight = weight;
    }
    friend double getTotalWeight(Boat &b, Car &c);
};

double getTotalWeight(Boat &b, Car &c)
{
    return b.weight + c.weight;
}

int main()
{
    Car c(4.5);
    Boat b(5.5);
    cout << "getTotalWight(b, c) = " << getTotalWeight(b, c) << endl;

    system("pause");
    return 0;
}

5-15 在函数内部定义的普通局部变量和静态局部变量在功能上有何不同?计算机底层对这两类变量做了怎样的不同处理,导致了这种差异?
局部作用域中的静态变量特点是:

  • 它不会随着每次函数调用而产生一个副本
  • 不会随着函数返回而失效
  • 默认以0进行初始化

二者底层方面的区别:

  • 普通局部变量存放于栈区超出作用域后, 变量被撤销, 内存被收回
  • 静态局部变量存放于静态数据存储区, 全局可见, 但是作用域是局部作用域, 超出作用域后, 变量依然存在

5-16 编译和连接这两个步骤的输人输出分别是什么类型的文件?两个步骤的任务有什么不同?
在以下几种情况下,在对程序进行编译、连接时是否会报错?会在哪个步骤报错?
(1) 定义了一个函数 void f(intx,inty),以f(1)的形式调用。
(2) 在源文件起始处声明了一个函数void f(intx),但未给出其定义,以f(1)的形式调用。
(3) 在源文件起始处声明了一个函数voidf(intx),但未给出其定义,也未对其进行调用。
(4) 在源文件a.cpp中定义了一个函数void f(intx),在源文件b.cpp中也定义了一个函数void f(intx),试图将两源文件编译后连接在一起。

编译:

  • 输入的是文件是源文件
  • 输出的是目标文件
  • 编译器将文本形式的源代码翻译为机器语言形式的目标文件

链接:

  • 输入的是目标文件
  • 输出的是可执行文件
  • 将各个编译单元的目标文件与运行库中被调用过的单元加以合并生成可执行文件

各个结果

  1. 编译时报错, 函数参数不匹配
  2. 链接时报错, 函数未定义
  3. 不报错
  4. 链接错误, 函数重复定义