4.3 调整基类成员在派生类中的访问属性的其他方法

4.3.1 同名函数

在定义派生类的时候,C++语言允许在派生类中说明的成员与基类中的成员名字相同,也就是
说,派生类可以重新说明与基类成员同名的成员。如果在派生类中定义了与基类成员同名的
成员,则称派生类成员覆盖了基类的同名成员,在派生类中重新说明的成员。为了在派生类
中使用基类的同名成员,必须在该成员名之前加上基类名和作用域标识符“::”,即必须使
用下列格式才能访问到基类的同名函数。
基类名::成员名
下面的程序片段说明了这个要点

class X{
public:
int f();
};
class Y:public X{
public:
int f();
int g();
};
void Y::g()
{
f(); //表示要访问的是派生类中的成员f(),即被调用的函数是Y::f()
X::f() //表示要访问基类中的f()
}
对于派生类的对象的访问,也有相同的结论。例如;
Y obj;
obj.f(); //被访问的函数是Y::f()
如果要访问基类中的声明的名字,则应使用作用域标识符限定,例如;
obj.X::f(); //被访问的函数是X::f()

//例4.10 在派生类中定义同名成员

#include<iostream>
#include<string>
using namespace std;
class Student{ //声明基类Student
public:
Student(int number1,string name1,float score1) //基类的构造函数
{
number = number1;
name = name1;
score = score1;
}
void print() //在基类中定义了成员函数print
{
cout<<"number:"<<number<<endl;
cout<<"name:"<<name<<endl;
cout<<"score:"<<score<<endl;
}
protected:
int number; //学号
string name; //姓名
float score; //成绩
};
class UStudent:public Student{
public:
UStudent(int number1,string name1,float score1,string major1):Student(number1,name1,score1)
{ //定义派生类的构造函数,缀上基类的构造函数
major = major1;
}
void print() //在派生类中重新定义了成员函数print
{
Student::print(); //调用基类Student的成员函数print
cout<<"major:"<<major<<endl;
}
private:
string major;
};
int main()
{
//Student stu(22116,"张志",95);
//stu.print(); //调用基类中的成员函数print
UStudent obj(,"张志",,"信息安全");
obj.print(); //调用派生类中的成员函数print
//obj.Student::print(); //调用基类中的成员函数print
return ;
}

4.3.2 访问声明
对于公有继承,基类的公有成员函数也就是派生类的公有成员函数,这意味着外界可以用派生类
的对象调用基类的公有成员函数。但是对于私有继承,基类的公有成员函数变成了派生类的私有
成员函数。这时,外界就无法利用派生类的对象直接调用基类的成员函数,而只能通过调用派生类
的成员函数(内含调用基类成员函数的语句)间接地调用基类的成员函数。

//例4.11 访问声明的引例

#include<iostream>
using namespace std;
class A{ //声明基类A
public:
A(int x1)
{
x = x1;
}
void print()
{
cout<<"x="<<x<<endl;
}
private:
int x;
};
class B:private A{ //声明私有派生类B
public:
B(int x1,int y1):A(x1)
{
y = y1;
}
void print2() //通过派生类B的函数print2来调用基类A的成员函数print
{
//print();
A::print();
}
private:
int y;
};
int main()
{
B b(,);
b.print2();
return ;
}
*/
/*
运行结果是:x=10 如果将派生类中的语句
void print2(){print()};
改写成语句
void print2(){A::print()};
同时,将主函数main()中的语句
b.print2();
改写成语句
b.print();
程序的运行结果不会变。
*/

这就是在4.3.1节中介绍过的方法。这种方法虽然执行起来比较简单,但在实际应用中却可能带来不便。有时程序员可能希望通过基类A的个别成员还能被派生类的对象直接访问,而不是通过派生类的公有成员函数间接访问。为此,C++提供了称为访问声明的特殊机制,可个别调整基类的某些成员,使之在派生类中保持原来的访问属性。访问声明的方法就是把某些基类的保护成员或公有成员直接写至派生类定义式中的同名段中,同时给基类名和作用域标识符::,利用这种方法,该成员就成为派生类的保护成员或公有成员了。

例如,把上面的基类中的print函数以A::print的形式直接写到私有派生类B中。

class B:private A{
public:
B(int x1,int y1):A(x1)
{
y = y1;
}
A::print; //访问声明
private:
int y;
};
这样,基类A中的print函数就调整为派生类B的公有成员函数,外界可以直接调用它了。
--------------------------------------------------------------- //例4.12 访问声明的应用
#include<iostream>
using namespace std;
class A{ //声明基类A
public:
A(int x1)
{
x = x1;
}
void print()
{
cout<<"x="<<x<<endl;
}
private:
int x;
};
class B:private A{ //声明私有派生类B
public:
B(int x1,int y1):A(x1)
{
y = y1;
}
A::print; //访问声明,把基类的公有成员函数print调整为私有派生类的
//公有成员函数
private:
int y;
};
int main()
{
B b(,);
b.print(); //调用基类的成员函数print
return ;
}

访问声明机制可以在私有派生类中个别调整从基类继承下来的成员性质,从而使外界可以通过
派生类的界面直接访问基类的某些成员,同时也不能影响其他基类成员的封闭性。
访问声明在使用时应注意以下几点。

(1)数据成员也可以使用访问声明。例如

class A{
private:
...
public:
int x2;
...
};
class B:private A{
private:
...
public:
A::x2; //把基类中的x2调整为派生类的公有成员
...
};

(2)访问声明中只含不带类型和参数的函数名或变量名。如果把上面的访问声明写成

   void A::print;

A::print();

void A::print();
都是错误的。

(3)访问声明不能改变成员在基类中的访问属性,也就是说,访问声明只能把原基类的保护成员调整为私有派生类中的保护成员,把原基类中的公有成员调整为调整为私有派生类中的公有成员。但是对基类的私有成员不能使用访问声明。

例如:

 class A{
private:
int x3;
public:
int x1;
protected:
int x2;
};
class B:private A{
private:
A::x3; //错误
protected:
A::x1; //错误
A::x2; //正确
A::x3; //错误
public:
A::x1; //正确
A::x2; //错误
A::x3; //错误
};

(4)对于基类中的重载函数名,访问声明将基类中的所有同名函数起作用。这意味着对于重载函数使用访问声明是要慎重。

C++:调整基类成员在派生类中的访问属性的其他方法(同名成员和访问声明)的更多相关文章

  1. C++中的类继承(2)派生类的默认成员函数

    在继承关系里面, 在派生类中如果没有显示定义这六个成员 函数, 编译系统则会默认合成这六个默认的成员函数. 构造函数. 调用关系先看一段代码: class Base { public : Base() ...

  2. 3.3 C++改变基类成员在派生类中的访问属性

    参考:http://www.weixueyuan.net/view/6360.html 总结: 使用using声明可以改变基类成员在派生类中的访问属性. private: using book::se ...

  3. c++基础(二):成员he派生类

    struct Date{ int day, month, year; }; struct Book{ string name; Date date; void init(string n, int y ...

  4. 【python 3.6】类:访问属性及调用方法

    >>> class price(): //定义1个类,用于计算价格 def __init__(self,name,danjia): //初始化方法,定义商品名称和单价 self.na ...

  5. c#序列化基类(包含派生类继承DynamicObject和 IXmlSerializable)对象

    直接上代码 using System.Diagnostics; using System.Text; using System.Xml; using System.Xml.Schema; using ...

  6. 哈希算法和字典类的定义,DataSet中数据遍历的几种方法

    哈希算法的基本操作: 1.  哈希表(HashTable)简述   在.NET Framework中,Hashtable是System.Collections命名空间提供的一个容器,用于处理和表现类似 ...

  7. 不可或缺 Windows Native (21) - C++: 继承, 组合, 派生类的构造函数和析构函数, 基类与派生类的转换, 子对象的实例化, 基类成员的隐藏(派生类成员覆盖基类成员)

    [源码下载] 不可或缺 Windows Native (21) - C++: 继承, 组合, 派生类的构造函数和析构函数, 基类与派生类的转换, 子对象的实例化, 基类成员的隐藏(派生类成员覆盖基类成 ...

  8. c++中派生类对基类成员的三种访问规则(转)

    C++中派生类对基类成员的访问形式主要有以下两种:1.内部访问:由派生类中新增成员对基类继承来的成员的访问.2.对象访问:在派生类外部,通过派生类的对象对从基类继承来的成员的访问.今天给大家介绍在3中 ...

  9. C++学习之路—继承与派生(一):基本概念与基类成员的访问属性

    (本文根据<c++程序设计>(谭浩强)总结而成,整理者:华科小涛@http://www.cnblogs.com/hust-ghtao,转载请注明) 1   基本思想与概念 在传统的程序设计 ...

随机推荐

  1. Freemarker例子

    1.引入架包 2.写ftl文件 3.代码 hello.ftl 你好啊,${hello},今天你的精神不错! if else 语句测试 <#if num gt 18><#-- 不使用 ...

  2. C# 命名参数【转】

    命名参数(Named Arguments)就是说在调用函数时可以通过指定参数名称的方式来调用参数.它最大的好处就是方便调用参数时按调用者的需要来排列顺序,而不必死守函数声明时的顺序(相对于“位置参数” ...

  3. Mysql数据库中的计数器表实时更新

    如果某个应用中存在计数器,例如网站的总访问量.用户的粉丝数.文件下载数等等.如果相关应用在Mysql数据库的表中保存计数器,在更新计数器的时候可能会碰到并发问题.例如在web应用中,记录网站的点击次数 ...

  4. java实现合并两个已经排序的列表

    相对于C++来说,Java的最大特点之一就是没有令人困惑的指针,但是我们不可否认,在某些特定的情境下,指针确实算的上一把利刃.虽然Java中没有明确定义出指针,但是由于类的思想,我们可以使用class ...

  5. andriod ADB命令的使用

    android ADB命令的使用 ADB是一个 客户端-服务器端 程序, 其中客户端是你用来操作的电脑, 服务器端是android设备. 先说安装方法, 电脑上需要安装客户端. 客户端包含在sdk里. ...

  6. Scrum10-22

    Time:2013-10-22 Author:居玉皓 Things we have done since yesterday's meeting: 在今天的Scrum中,STORY1 开发前期准备工作 ...

  7. VMware虚拟机中Hadoop服务的端口无法访问的问题

    今天安装了一个hadoop集群,因为已经在单个虚拟机上安装成功,所以初期安装相对顺利. 初始环境如下:       通过Vmware Esxi服务器虚拟机出来四台机器,每台机器的网络配置如下:     ...

  8. WinForm点击按钮在对应的panel里画图

    panel在form1里,button在form1上方,panel在下面. 主要是在button1的click时间获取panel的画笔. 下面的不行,在panel里获取画笔,然后传到button1,根 ...

  9. 如何将jsp中<input>设为只读

    将一个input变为只读,可以使用 readonly 属性 和 disabled 属性.  用disabled 属性时,文字显示为灰色.  下面的两种方法都是可以的: <input id =&q ...

  10. Asp.net 程序部署问题——在应用程序级别之外使用注册为 allowDefinition='MachineToApplicati错误信息

    [转]在应用程序级别之外使用注册为 allowDefinition='MachineToApplicati 错误信息: ======================================== ...