C++ 继承体系中的名称覆盖

首先一个简单的样例:

int x;
int f()
{
    double x;
    cin >> x;
    return x;
}

在上述代码中。函数f的局部变量x掩盖了全局变量x。这得从 “C++的名字查找机制“说起,首先。在函数f的局部作用域中查找。(甚至是语句块)。假设不存在,到上一层的作用域再进行查找,... 该命名空间中查找,最后是全局作用域。

在类的继承体系中,名字覆盖问题也是非常困扰的。此处的"名字"但是是函数名,变量名,typedef, enum都能够,此处以函数名为例。

值得注意的是,Derived的作用域是嵌套在Base作用域中的。

对于以下的代码:

class Base
{
public:
  //对于C++类中定义的不论什么类型的函数,名字覆盖的规则都是一样的。
  virtual void func1(int x){cout << "func1(int) in Base ..." << endl;}
  void func2(){cout << "func2() in Base ..." << endl;}
  virtual void func3() = 0;
};

class Derived : public Base
{
public:
  void func1() {cout << "func1() in Derived..." << endl;}
  void func2(int x) {cout << "func2(int) in Derived..." << endl;}
  void func3() {cout << "func3() in Derived..." << endl;}
  void func3(int ) {cout << "func3() in Derived..." << endl;}
};

int main()
{
  Derived d;
  d.func1(3); //调用失败。

编译器在Derived的作用域中找到了该函数名字,可是发现调用不匹配,不能通过编译
  d.func2();
  return 0;
}

Base基类中定义了函数func1 与 func2,在派生类中重写了函数func1,并定义了该函数的重载版本号。

对于main函数内的调用,见凝视解析。

编译器在面对函数调用时,首先是在作用域范围内查找该函数名(由内之外)。 假设找到了该函数名之后。编译器便停止查找,開始检查形參与实參的匹配是否合法, 假设不合法,不能通过编译。

假设要在上述代码中调用 基类中的版本号 func1(int),那么就须要让编译器在看到该函数调用时,第一时间看到base中的该函数名字,因此。using声明攻克了这个难题,在Derived类定义体内部使用using base::func1声明,也就是让Base中的func1函数名字在  ”编译器查找Derived“作用域是可见 。

using的位置放在哪里???。!!

非常easy的道理,public继承 意味 ”  is   a   “的关系,那么在Base class中的 public的名称在Derived中也应该是public。

可是,假设你并不想继承 Base中的全部的函数,仅仅想继承一部分,那么   这就无关于函数名字的问题了。 既然如此。public继承就不应该被使用!

因此,我会告诉你。使用private继承也许有这种福利。

如果Derived以private形式继承Base。而Derived中仅仅想要继承Base中的某个特定的函数版本号,那么using已经无论用了,你须要的是其它的技术。

比如以下的简单样例:

class Base
{
public:
    void func1(){cout << "func1 in Base" << endl;}
};
class Derived : public Base
{
public:
    void func1()
    {
        Base::func1(); //转交函数,相当于将func1 in Base 转交给func1  in Derived
    }
};

最后。在C++的名字查找中。为了避免Base的函数名覆盖,使用using 声明或者转交函数来完毕。

时间: 2024-10-13 16:05:41

C++ 继承体系中的名称覆盖的相关文章

关于Java继承体系中this的表示关系

Java的继承体系中,因为有重写的概念,所以说this在子父类之间的调用到底是谁的方法,或者成员属性,的问题是一个值得思考的问题; 先说结论:如果在测试类中调用的是子父类同名的成员属性,这个this.成员  属性的值就是父类中这个成员属性的值,因为在Java中没有重写成员属性这一概念 ,如果调用的是同名的成员方法的话,那就应该调用的是重写后的成员方法.....如果子类中没有这个成员方法,则向父类中寻找. 上代码支持论证: package Test_This; public class Demo

JAVA设计模式-装饰设计模式-继承体系的由来和装饰类的优化

首先看一下我们设计类的过程: 专门用于读取数据的类 MyReader l--MyTextReader:根据不同的功能会不断延伸很多子类 l--MyMeidaReader l--MyDataReader l--.......... 为了提高以上子类的工作效率,需要加入缓冲区技术.所以又会出现下面的类的继承体系. (体系1) MyReader l--MyTextReader:根据不同的功能会不断延伸很多子类 l--MyBufferedTextReader l--MyMeidaReader l--My

继承中方法的覆盖

执行下边的代码: class Parent2{ public void Print() { System.out.println("今天是个好日子!!"); } } class Child2 extends Parent2{ public void Print() { //super.Print(); System.out.println("今天不是个好日子!!"); } } public class super1 { public static void main

Effective C++:条款33:避免遮掩继承而来的名称

(一) 下面这段代码: int x; void someFunc() { double x; //local variable std::cin>>x; //read a new value to local x } 这个指涉的是local变量x,而不是global变量x,因为内存作用域会的名称遮掩外围作用域的名称.当编译器处于someFunc的作用域内并遭遇名称x时,他在local作用域内查找是否有什么东西带着这个名称.如果找到就不再找其他作用域.someFunc的x是double类型而gl

Java技术_Java千百问(0038)_java中重载和覆盖有什么关系

点击进入_更多_Java千百问 1.什么是重载 java的重载,简单说,就是方法有同样的名称,但是参数不相同.这样的同名不同参数的方法之间,互相称之为重载方法. 需要注意的是: 1. 方法名相同. 2. 参数不同,这里是说对应位置的参数类型至少有一个不同,当然List和List都是List,算作相同. 3. 返回值可以不同,可以相同. 例子: "` public class Test{ public void a() { System.out.println("a()");

条款33:避免遮掩继承而来的名称

首先看下下面这个例子: class Base{ private: int x; public: virtual void mf1() = 0; virtual void mf2(); void mf3(); ... }; class Derived : public Base{ public: virtual void mf1(); void mf4(); ... }; 这个函数里面还有纯虚函数,虚函数以及非虚函数. 如果这里derived class调用了一个mf2函数的话,那么那么会先在de

继承类中static数据值

1 class A{ 2 static int num = 1; 3 public static void Display(){ 4 System.out.println( num ); 5 } 6 } 7 8 class B extends A{ 9 static int num = 2; 10 public static void Display(){ 11 System.out.println( num ); 12 } 13 } 14 15 class C extends A{ 16 st

CSS中的样式覆盖原则

规则一:由于继承而发生样式冲突时,最近祖先获胜(最近原则).CSS的继承机制使得元素可以从包含它的祖先元素中继承样式,考虑下面这种情况: <html> <head> <title>rule 1</title> <style> body {color:black;} p {color:blue;} </style> </head> <body> <p>welcome to <strong>

Entity Framework 6 Recipes 2nd Edition(10-7)译 -&gt; TPH继承模型中使用存储过程

10-7. TPH继承模型中使用存储过程 问题 用一个存储过程来填充TPH继承模型的实体 解决方案 假设已有如Figure 10-7所示模型. 我们有两个派生实体: Instructor(教员)和Student(学生). 这个模型使用TPH继承方式,所以数据库中只有一个表. Person(人员)表有一个鉴别列,用来把表的记录映射到不同的派生实体上. 我们想用一个存储过程来填充实体. Figure 10-7. A model for instructors and students 用下面的步骤,