重温《C++ Primer》笔记五 类定义中成员函数的名字隐藏(虚函数与非虚函数)

类定义中大致有两种函数——普通函数和虚函数。如果对一个类继承并且对其中的成员函数重新进行定义,也可以分为两种情况:

1、在派生类的定义中明确地定义操作和返回类型,称之为普通成员函数的重定义(redefining);

2、对虚函数的重定义成为重写(overriding);

下面的程序是摘自《Thinking in C++》上的一段,可以用来解释发生在函数重定义过程中的名字隐藏(这里的名字指的是函数的名字):

#include 
#include 
using namespace std;

class Base{
public:
	int f() const
	{
		cout<<"Base::f()\n";
		return 1;
	}
	int f(string) const {return 1;}
	void g() {}
};

class Derived1 : public Base{
public:
	void g() const {}
};

class Derived2 : public Base{
public:
	int f() const
	{
		cout<<"Derived2::f()\n";
		return 2;
	}
};

class Derived3 : public Base{
public:
	void f() const
	{
		cout<<"Derived3::f()\n";
	}
};

class Derived4 : public Base{
public:
	int f(int) const
	{
		cout<<"Derived4::f()\n";
		return 4;
	}
};

int main()
{
	string s("hello");
	
	Derived1 d1;
	int x = d1.f();
	d1.f(s);
	
	Derived2 d2;
	x = d2.f();
	d2.f(s);
	
	return 0;
}
首先,Derived1只重定义了父类的g()函数,没有对f()函数做任何的改变,因此调用f()的时候会自动调用父类的f()。并且f(s)在Derived1中也是可以使用的。

对于Derived2,它重定义了f()函数,而没有重定义f(s)函数,但是在这里却只能调用f()而不能调用f(s),即f(s)被隐藏了。

如果对Derived2修改一下,即重定义f()函数,也重定义f(s)函数,则两种都可以调用。

对于Derived3,它没有重定义基类中名为f的任何函数,而是通过修改返回值类型自己重新定义了一个名为f的函数,导致基类中的两个名为f的函数均不能被调用,即均被隐藏了。

对于Derived4,它没有重定义基类中名为f的任何函数,而是通过修改参数自己重新定义一个名为f的函数,导致基类中的两个名为f的函数均不能被调用,即均被隐藏了。

因此,可以得出一个结论:任何时候重新定义了基类中的一个重载函数,在新类之中所有其他的版本则被自动隐藏,除非在子类中全部重定义。


而对于虚函数的重写则有一点不同,即编译器不允许我们改变重定义过的函数的返回值类型(除了是将从基类引用或指针改为子类引用或指针),其它的则与重定义遵循一样的规则。这是为什么呢?在《Thinking in C++》上是这么说的:“因为编译器必须保证我们能够动态地通过基类调用函数,并且如果基类希望f()返回一个int值,则f()的派生类版本必须保持约定,否则将会出问题”。




你可能感兴趣的:(C++,重温《C++,Primer》笔记)