Effective C++ Item 33 避免遮掩继承过来的名称

本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie

? 不懂 c++为什么derived classes 内的名称要遮掩 base classes 内的名称。

经验:derived classes 内的名称会遮掩 base classes 内的名称。在 public 继承下从来没有人希望如此。

C++ 的名称遮掩规则所做的唯一事情就是: 遮掩名称

derived class 作用域被嵌套在 base class 作用域里

class Base {
private:
	int x;
public:
	virtual void mf1() = 0;
	virtual void mf1(int);
	virtual void mf2();
	void mf3();
	void mf3(double);
	//...
};

class Derived: public Base{
	virtual void mf1() {};
	void mf3();
	void mf4();
	//...
};

Derived d;
int x;
d.mf1();  //ok. 调用 Derived::mf1
d.mf1(x); //error. 因为Derived::mf1遮掩了 Base::mf1
d.mf2();  //ok. 调用 Base::mf2
d.mf3();  //ok. 调用 Derived::mf3
d.mf3(x); //error. 因为Derived::mf3遮掩了 Base::mf3

解析:

名称遮掩原则

int x, double x的名称都是x,

void mf(double x) ,void mf()的名称都是mf

纠正1:使用 using 声明式

class Base{
private:
	int x;
public:
	virtual void mf1() = 0;
	virtual void mf1(int);
	virtual void mf2();
	void mf3();
	void mf3(double);
	//...
};
class Derived: public Base{
public:
	using Base::mf1; //让 Base class 内名为mf1和mf3的所有东西在 Derived 作用域内都可见(并且 public)
	using Base::mf3;
	virtual void mf1();
	void mf3();
	void mf4();
	//...
};

Derived d;
int x;
d.mf1();  //ok. 调用 Derived::mf1
d.mf1(x); //ok. Base::mf1
d.mf2();  //ok. 调用 Base::mf2
d.mf3();  //ok. 调用 Derived::mf3
d.mf3(x); //ok. Base::mf3

纠正2:转交函数(forwarding function)

class Base{
private:
	int x;
public:
	virtual void mf1() = 0;
	virtual void mf1(int);
	//...  与前同
};
class Derived: private Base{
	virtual void mf1() //转交函数
	{Base::mf1();}
};

Derived d;
int x;
d.mf1(); //ok. 调用的是 Derived::mf1
d.mf1(x);//error. Base::mf1()被遮掩了

Effective C++ Item 33 避免遮掩继承过来的名称,布布扣,bubuko.com

时间: 2024-08-03 14:16:58

Effective C++ Item 33 避免遮掩继承过来的名称的相关文章

Effective C++ Item 36 绝不重新定义继承而来的 non-virtual 函数

本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 经验:绝对不要重新定义继承而来的 non-virtual 函数 --> Item 7 "为多态基类声明 virtual 析构函数" 是本条款的特例 示例: class B{ public: void mf(); //... }; class D: public B{ public: void mf(); // 遮掩了B::mf,Item 33 名称遮掩规则 } D x; B

Effective C++ Item 34 区分接口继承与实现继承

本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 关联条款 Item 36 接口继承和实现继承不同.在 public 继承下, derived classes 总是继承 base class 的接口 class Shape{ public: virtual void draw() const = 0; virtual void error(const std::string &msg); int objectID() const; //.

Effective C++ Item 37 绝不重新定义继承而来的缺省参数值

本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 经验:绝对不要重新而来的缺省参数值,因为缺省参数值都是静态绑定,而 virtual 函数 -- 你唯一应该覆写的东西 -- 却是动态绑定 示例: class Shape{ public: enum ShapeColor {Red, Green, Blue}; virtual void draw(ShapeColor color = Red) const = 0; }; class Rect

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

首先介绍一个原则LSP(Liskov Substitution Principle),如果Class D以Public方式继承Class B,则所有B对象可以派上用场的任何地方,D对象一样可以派上用场. 对于重载和重写,相信大家都已经有所了解.这里讨论一下在public继承的时候,重载函数的问题. 先看下面的例子: 1 class Base 2 { 3 public: 4 virtual void mf1() = 0; 5 virtual void mf1(int); 6 virtual voi

读书笔记 effective c++ Item 32 确保public继承建立“is-a”模型

1. 何为public继承的”is-a”关系 在C++面向对象准则中最重要的准则是:public继承意味着“is-a”.记住这个准则. 如果你实现一个类D(derived)public继承自类B(base),你在告诉c++编译器(也在告诉代码阅读者),每个类型D的对象也是一个类型B的对象,反过来说是不对的.你正在诉说B比D表示了一个更为一般的概念,而D比B表现了一个更为特殊的概念.你在主张:任何可以使用类型B的地方,也能使用类型D,因为每个类型D的对象都是类型B的对象:反过来却不对,也就是可以使

Effective JavaScript Item 33 让构造函数不再依赖new关键字

本系列作为EffectiveJavaScript的读书笔记. 在将function当做构造函数使用时,需要确保该函数是通过new关键字进行调用的. function User(name, passwordHash) { this.name = name; this.passwordHash = passwordHash; } 如果在调用上述构造函数时,忘记了使用new关键字,那么: var u = User("baravelli", "d8b74df393528d51cd19

Effective C++ Item 44 将与参数无关的代码抽离 templates

本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 经验:Templates 生成多个 classes 和多个函数,所以任何 template 代码都不该与某个造成膨胀的 template 参数产生相依关系 因非类型模板参数(non-type template parameters) 而造成的代码膨胀,往往可消除,做法是以函数参数或 class 成员变量替换 template 参数 示例: template<typename T, std:

Effective C++ Item 44 将与參数无关的代码抽离 templates

本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 经验:Templates 生成多个 classes 和多个函数,所以不论什么 template 代码都不该与某个造成膨胀的 template 參数产生相依关系 因非类型模板參数(non-type template parameters) 而造成的代码膨胀,往往可消除,做法是以函数參数或 class 成员变量替换 template 參数 演示样例: template<typename T,

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