面向对象程序设计问答题OOP10-11继承


0. 知识点

基类成员在派生类中外部能见度


继承下的公有/私有成员


继承下的保护成员


基类成员在派生类中内部能见度


不同情况下的对派生类构造函数要求

1. 类中的成员可以用public/protected/private分别进行修饰,这三种成员在什么情况下是可以被访问的?

类中没有用public/protected/private修饰的成员,其可访问性是什么,结构体中没有用public/protected/private修饰的成员,其可访问性是什么?

见$OOP5$面向对象概论问题$3$,此处为了方便将其复制过来

  • $public$: 修饰的成员可以在任何地方被访问
  • $private$: 修饰的成员只能由该类中的函数、其友元函数访问,不能被任何其他访问,该类对象也不能访问
  • protected: 修饰的成员可以被该类中函数子类函数友元函数访问;但不能被该类对象访问
  • 中没有用$public/protected/private$修饰的成员,其可访问性默认是$private$
  • 结构体中没有用$public/protected/private$修饰的成员,其可访问性默认是$public$

2. 什么是封装?其作用是什么?

见$OOP4$面向对象概论问题$2$,此处为了方便将其复制过来

  • 封装: 封装是将抽象得到的数据和行为(或功能)相结合,形成一个有机的整体,也就是将数据与操作数据的函数代码进行有机结合,形成类。

  • 作用: 使一部分成员充当类与外部的接口,而将其他成员隐藏起来,这样就达到了对成员访问权限的合理控制,使不同类之间的相互影响减少到最低限度,进而保护数据增强数据的安全性和简化程序编写工作。

3. 若父类中没有缺省构造函数,则对派生类的构造函数有什么要求?

  • 要求: 派生类含有构造函数,且要对父类通过初始化列表进行构造.
  • 原因: 父类中没有缺省构造函数,假设派生类无构造函数(即只有编译器提供的缺省构造函数),那么就不会先自动构造父类的构造函数,这是不允许的。

4. 构造函数的作用是什么?什么时候会被调用?构造函数的执行顺序是什么?

(父类与子类的构造函数、类自身与其数据成员的构造函数)

见$OOP7$面向对象概论问题$2$,此处为了方便将其复制过来

  • 作用: 用来在对象实例化的时候初始化对象的成员变量
  • 调用时间: 当类被创建时,自动调用构造函数
  • 执行顺序: 先执行父类的构造函数,再执行数据成员的初始化(成员中有类,执行该类的构造函数),最后执行子类的构造函数

5. 什么是初始化列表(Initialization Sections)?它的作用是什么?

(提示:一般数据成员的初始化、常成员的初始化,对象成员构选函数的选择、父类构造函数的选等)

见$OOP7$面向对象概论问题$6$,此处为了方便将其复制过来

  • 初始化列表($Initialization$ $Sections$):与其他函数不同,构造函数除了有名字,参数列表和函数体之外,还可以有初始化列表,初始化列表以冒号开头,后跟一系列以逗号分隔的初始化字段。
class foo{
public:
     // 初始化列表
    foo(string s, int i): name(s), id(i){} ;
private:
    string name ;
    int id ;
};
  • 作用:
  1. 初始化一般数据成员(如上例)
  2. 初始化常量成员(原因:常量只能初始化不能赋值,所以必须放在初始化列表中)
  3. 初始化引用类型(原因:引用必须在定义的时候初始化,并且不能重新赋值,所以也要写在初始化列表里面)
  4. 初始化没有缺省构造函数的类类型(原因:使用初始化列表可以不必调用默认构造函数来初始化,而是直接调用拷贝构造函数初始化)
    举例:类A的对象a是类B的数据成员
#include <iostream> 
using namespace std; 

class A { 
    int i; 
public: 
    A(int ); 
}; 

A::A(int arg) { 
    i = arg; 
    cout << "A's Constructor called: Value of i: " << i << endl; 
} 

// Class B contains object of A 
class B { 
    A a; 
public: 
    B(int ); 
}; 

B::B(int x):a(x) { //Initializer list must be used 
    cout << "B's Constructor called"; 
} 

int main() { 
    B obj(10); 
    return 0; 
} 
/* OUTPUT: 
    A's Constructor called: Value of i: 10 
    B's Constructor called 
*/
  1. 初始化基类成员(父类成员)
#include <iostream> 
using namespace std; 

class A { 
    int i; 
public: 
    A(int ); 
}; 

A::A(int arg) { 
    i = arg; 
    cout << "A's Constructor called: Value of i: " << i << endl; 
} 

// Class B is derived from A 
class B: A { 
public: 
    B(int ); 
}; 

B::B(int x):A(x) { //Initializer list must be used 
    cout << "B's Constructor called"; 
} 

int main() { 
    B obj(10); 
    return 0; 
} 
  1. 当构造函数的参数名称与数据成员相同,必须使用this指针或初始化列表初始化数据成员。
#include <iostream> 
using namespace std; 

class A { 
    int i; 
public: 
    A(int ); 
    int getI() const { return i; } 
}; 

A::A(int i):i(i) { } // Either Initializer list or this pointer must be used 
/* The above constructor can also be written as 
A::A(int i) { 
    this->i = i; 
} 
*/

int main() { 
    A a(10); 
    cout<<a.getI(); 
    return 0; 
} 
/* OUTPUT: 
    10 
*/

6. 如何防止一个头文件被多重包含?举例说明。

见$OOP1-003$面向对象概论问题$8$,此处为了方便将其复制过来

使用条件编译

假设包含的文件名为x.h,写成如下:

#ifndef _x_h
#define _x_h
//...其他内容

#endif

7. 父类成员中的public、protected、private成员,哪些在子类中是可以访问的?在公有继承、私有继承、受保护继承三种继承方式下,父类成员中的public、protected、private成员被继承到子类后,其可访问性分别是什么?派生类是否可以继承父类的构造函数和析构函数?

  • 父类的$public$、$protected$可以在子类中进行访问,而父类的$private$不可以在子类中访问
  • 对外: (顺序为$public$、$protected$、$private$)

公有继承(透明): $public$ 、$protected$ 、 $private$
受保护继承(半透明): $protected$ 、$protected$ 、$private$
私有继承(不透明): $private$ 、$private$ 、 $private$

  • 派生类不可以继承父类的构造函数和析构函数

8. 多重继承会带来什么问题?在C++中是如何解决的?

class BC0 {
    public:   int K;
};
class BC1 : public BC0 {
    public:  int x;
};
class BC2 : public BC0 {
     public:   int x;
};
class  DC : public BC1, public BC2{
};
  • 问题$1$: 派生类中的对象中存在多个同名成员问题,该怎么解决?

类DC的对象中存在多个同名成员 x, 应如何使用?

  • 解决方案:
d.BC1::x = 11; // from BC1
d.BC2::x = 12; // from BC2
  • 问题$2$: 派生类的对象中存在来自同一个类的成员,该如何区分?

类DC的对象中,存在两份来自类BC0的成员K,如何区分?

  • 解决方案: 采用虚继承的方式解决
class BC0 {
    public:   int K;
};
class BC1 : virtual public BC0 {
    public:  int x;
};
class BC2 : virtual public BC0 {
    public:   int x;
};
class  DC : public BC1, public BC2{
    public:  int x;
};

// 虚继承使得BC0仅被DC间接  
// 继承一份
d.BC0::K = 13; // O.K.

文章作者: 保底不歪抽早柚
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 保底不歪抽早柚 !
评论
  目录