北京大学程序设计MOOC作业详解-03-类和对象提高

北京大学程序设计MOOC作业详解-03-类和对象提高

第一题:

在这里插入图片描述

第一题分析:

这个题考察C++面向对象在C语言下是如何表示的,C++程序是可以“翻译”成C语言再进行编译的,那如何完成这个“翻译”过程呢?

1)class 类类型会翻译成struct 结构体类型,成员变量是结构体的域;
2)非静态成员函数,会翻译成多带一个指针变量的函数,这个指针变量,指向被操作的对象(结构体变量),这是因为非静态成员函数要能访问成员变量;
3)那静态成员函数呢?其实C++的static可以看作是C的static,即当前文件的全局变量,而静态成员函数则是引用文件的代码区内都可以访问的函数;

值得注意的是,静态成员变量/函数是属于类的,而非静态成员变量/函数是属于对象的。而C++中,这个操作对象的指针,被称作this指针,显然是要先有对象,才会有this指针。而静态成员在类声明阶段就有了,可能此时并没有实例化出对象,因此不会有this指针

this指针的值,就是对象的起始地址。并且,调用成员函数时,系统会隐式地将对象的起始地址当作this指针传递给函数。因此,类不会单独开辟空间存放this指针,只是函数调用时将地址(整数)传递给了非静态成员函数。综上所述,本题选C

第二题:

在这里插入图片描述

第二题分析:

这个题考察静态与非静态成员变量/函数的访问权限,具体知识点我们已经在第一题分析过了,这里总结一下:

1)静态成员是属于类的,只要类定义了,即使没有实例化出对象,也能访问静态成员,访问的方式是:类名::,这个“::”叫作用域限定符
2)静态成员是所有对象所共享的,这一点很关键,后面还会再提;
3)类和对象有先后关系,一定是先定义类,后实例化对象,因此对象一定可以访问静态成员;
4)有对象一定有类,但是有类不一定有对象。所以,静态成员函数不能访问非静态成员变量或非静态成员函数。

因此,本题选C

第三题:

在这里插入图片描述

第三题分析:

这个题考察封闭类,以及封闭类的初始化顺序,以及析构顺序。这里总结以下知识点:
1)封闭类的概念:就是一个类,里面的成员变量不是C++本身就有的数据类型,而是类类型变量/指针,这种就叫封闭类,例如:

#include <iostream>
using namespace std;

class A {
private:
	int a1, a2;
public:
	A(int a1_, int a2_) : a1(a1_), a2(a2_)
	{ cout << "A constructor" << endl; }
	~A() { cout << "A destructor" << endl; }
};

class B {
private:
	int b1, b2, b3;
public:
	B(int b1_, int b2_, int b3_) : b1(b1_), b2(b2_), b3(b3_)
	{ cout << "B constructor" << endl; }
	~B() { cout << "B destructor" << endl; }
};

class C {
private:
	B b;
	A a;
	int c1;
public:
	C(int c1_, int c2_, int c3_, int c4_, int c5_, int c6_) 
		: a(c1_, c2_), c1(c3_), b(c4_, c5_, c6_) {
		cout << "C constructor" << endl;
	}
	~C() { cout << "C destructor" << endl; }
};

int main() {
	C c(1, 2, 3, 4, 5, 6);
	/*
	* Output:
		B constructor
		A constructor
		C constructor
		C destructor
		A destructor
		B destructor
	*/
	return 0;
}

2)非指针的类成员对象,在包装类(上例的类C)中必须以初始化列表的形式进行实例化
3)但如果是指针类型类成员对象,那构造和析构的时机取决于new和delete调用的时机。需要注意:初始化列表先于构造函数调用,因此指针类型的类成员变量会较晚(但在包装类的构造函数之前)被调用;
4)重要:构造和析构的顺序,遵循两个原则,① 按照声明顺序进行构造,②先构造的后析构,除了指针对象和STL对象,STL对象能自行操控析构,这是因为底层还是指针实现。

理解1:一个对象的声明,即使未定义,也已经有了地址。在实例化的过程中,会遵循地址,优先实例化(构造)先声明的类成员对象。

理解2:这个地址在实例化之后,会指向一个存储在栈区的对象,栈是一种先进后出的结构。一个变量实例化,会进栈;析构则出栈。而出栈顺序和进栈顺序相反,因此会有“先构造的后析构”原则。

注意:以上均为个人理解,不一定正确,如有错误,或者未来我发现了错误,我会及时更正,也请各位看官提醒,谢谢!

言归正传,复习完封闭类后,看选项。
A选项:成员对象要比封闭类对象先构造,因此后析构,所以A不对;
B选项:根据上述分析,知道B选项正确;
C选项:实验和理论分析知道,成员对象的初始化顺序取决于声明顺序,与初始化列表的顺序无关;
D选项:成员对象的初始化要取决于具体的构造函数,如果是封闭类的拷贝构造,那就用拷贝构造初始化;如果是有参构造,那就用有参构造初始化,这是和封闭类以及类成员对象所属的类共同决定的。因此,本题选B

第四题:

在这里插入图片描述

第四题分析:

这个题考察友元的概念,先复习友元的相关知识点:
0)友元关系是指:能访问一方私有成员的关系,一般需要访问私有成员的有函数和类,因此有友元函数和友元类;
1)友元关系不是相互的,类A是类B的友元,反过来类B不是类A的友元;
2)友元关系的声明,是根据“供求关系”决定的。如果类A需要访问类B中的私有成员,则需要获得类B的授权,即需要类B声明类A是自己的友元
3)根据2)可知,友元关系请求方声明了没用,需要供应方声明;
4)在一个类中,是可以将另一个类的成员函数声明为友元的,用作用域限定符声声明。但前提是,必须要先声明成员函数,后在“供应方”类当中声明友元函数。

综上所述,本题选A

第六题:

第五题做过了,不再赘述,直接看第六题。
在这里插入图片描述

第六题分析:

类成员对象就和普通的成员变量一样对待,但是需要注意:如果类及封闭类的成员变量中有指针类型,一定都要实现拷贝构造。一般在开发过程中,都有指针类型,最好都实现拷贝构造。

这是因为,在封闭类的拷贝构造函数中,一般还是以拷贝构造的方式初始化类成员对象。当然,也可以用普通构造函数。AC代码如下:

	Big(int n) : v(n), b(n) { }
	Big(const Big& obj) : v(obj.v), b(obj.b) { }

第七题:

在这里插入图片描述

第七题分析:

这个题,是不是和前面几道题有相似之处。本题需要获得类A的指针,即this指针。但是有一些细节:
1)获得的指针是常量指针,且是通过常量a调用函数getPointer()。注意到,常量不能调用非常量函数,这是因为非常量函数可能会修改成员变量的值。因此getPointer函数是长函数;
2)一个类中,如果函数是常函数,则传入常this指针。如果是非常函数,则传入普通的this指针。这里是常函数,所以this指针也是常量指针;
3)要返回这个常量指针,就必须由常量指针的返回类型,否则就是将常量返回到非常量了。但是反过来,将非常量返回给常量是可以的。

通过上述分析,AC代码如下:

const A* getPointer() const { return this; }

第八题:

魔兽世界(一):备战,请看我的题解

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值