引用、指针、多态、虚函数、重载

本文详细解释了C++中的引用、指针、多态、虚函数和重载概念,包括引用的规则、应用、与指针的区别,多态性的类型和特性,以及虚函数和重载的使用场景。

1、引用的说明

引用指的是对一个对象的引用。引用和用来初始化引用的变量指向的是同一块内存,因此通过引用或者变量可以改变同一块内存中的内容。引用一旦初始化,它就代表了一块特定的内存,再也不能代表其他的内存。

n是m的一个引用(reference),m是被引用物(referent)。 
int m; 
int &n = m; 
n相当于m的别名(绰号),对n的任何操作就是对m的操作。 
所以n既不是m的拷贝,也不是指向m的指针,其实n就是m它自己。 


2、引用的规则:
(1)引用被创建的同时必须被初始化(指针则可以在任何时候被初始化)。 
(2)不能有NULL引用,引用必须与合法的存储单元关联(指针则可以是NULL)。 
(3)一旦引用被初始化,就不能改变引用的关系(指针则可以随时改变所指的对象)。 
以下示例程序中,k被初始化为i的引用。 
语句k = j并不能将k修改成为j的引用,只是把k的值改变成为6。 
由于k是i的引用,所以i的值也变成了6。 

int i = 5; 
int j = 6; 
int &k = i; 
k = j; // k和i的值都变成了6; 

3、引用的应用

引用的主要功能是传递函数的参数和返回值。 

引用作为参数,一是避免在实参占较大内存时发生值的复制,二是完成一些特殊的作用,例如,要在函数中修改实参所指向内存中的内容。

引用作为返回值,

C++语言中,函数的参数和返回值的传递方式有三种:值传递、指针传递和引用传递。 
以下是"值传递"的示例程序。 
由于Func1函数体内的x是外部变量n的一份拷贝,改变x的值不会影响n, 所以n的值仍然是0。 

void Func1(int x) 
{ 
x = x + 10; 
} 
... 
int n = 0; 
Func1(n); 
cout << "n = " << n << endl; // n = 0 

以下是"指针传递"的示例程序。 
由于Func2函数体内的x是指向外部变量n的指针,改变该指针的内容将导致n的值改变,所以n的值成为10。 

void Func2(int *x) 
{ 
(* x) = (* x) + 10; 
} 
... 
int n = 0; 
Func2(&n); 
cout << "n = " << n << endl; // n = 10 

以下是"引用传递"的示例程序。 
由于Func3函数体内的x是外部变量n的引用,x和n是同一个东西,改变x等于改变n,所以n的值成为10。 

void Func3(int &x) 
{ 
x = x + 10; 
} 
... 
int n = 0; 
Func3(n); 
cout << "n = " << n << endl; // n = 10 

对比上述三个示例程序,会发现"引用传递"的性质象"指针传递",而书写方式象"值传递"。 
实际上"引用"可以做的任何事情"指针"也都能够做,为什么还要"引用"这东西? 
答案是"用适当的工具做恰如其分的工作"。 
指针能够毫无约束地操作内存中的任何东西,尽管指针功能强大,但是非常危险。 
如果的确只需要借用一下某个对象的"别名",那么就用"引用",而不要用"指针",以免发生意外。

4、引用与指针的关系

引用只是一个别名,是一个变量或对象的替换名称。引用的地址没有任何意义,因此C++没有提供访问引用本身地址的方法。引用的地址就是它所引用的变量或者对象的地址,对引用的地址所做的操作就是对被引用的变量或对象的地址所做的操作。指针是地址,指针变量要存储地址值,因此要占用存储空间,我们可以随时修改指针变量所保存的地址值,从而指向其他的内存。

引用和指针变量的内存模型如下图所示:

引用和指针变量的内存模型

在编写程序时,很少直接使用引用,即用一个变量来初始化一个引用(int a; int &b=a),如果这么做,通过变量和引用都可以修改同一块内存的内容,在程序中,就很容易出现问题,不知道此时内存中的值到底是多少了。

5、多态、虚函数、重载

多态性

    在面向对象的概念中,多态性是指不同对象接收到相同消息时,根据对象类的不同产生不同的动作。多态性提供了同一个接口可以用多种方法进行调用的机制,从而可以通过相同的接口访问不同的函数。具体地说,就是同一个函数名称,作用在不同的对象上将产生不同的操作。

    多态性提供了把接口与实现分开的另一种方法,提高了代码的组织性和可读性,更重要的是提高了软件的可扩充性。

编译时的多态性和运行时的多态性

静态联编支持的多态性称为编译时的多态性或静态多态性,也就是说,确定同名操作的具体操作对象的过程是在编译过程中完成的。C++用函数重载和运算符重载来实现编译时的多态性,平常所说的overload(重载)。

动态联编支持的多态性称为运行时的多态性活动太多态性,也就是说,确定同名操作的具体操作对象的过程是在运行过程中完成的。C++用继承和虚函数来实现运行时的多态性,平常所说的override(重写、覆盖)。

下面是从别处拷贝过来的,出处不记得了

成员函数被重载的特征
(1)相同的范围(在同一个类中); 
(2)函数名字相同; 
(3)参数不同; 
(4)virtual 关键字可有可无。 
覆盖是指派生类函数覆盖基类函数,特征是
(1)不同的范围(分别位于派生类与基类); 
(2)函数名字相同; 
(3)参数相同; 
(4)基类函数必须有virtual 关键字。 
“隐藏”是指派生类的函数屏蔽了与其同名的基类函数,规则如下
(1)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)。 
(2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual 关键字。此时,基类的函数被隐藏(注意别与覆盖混淆) 

3种情况怎么执行:
重载:看参数
隐藏:用什么就调用什么
覆盖:调用派生类

 

posted on 2014-03-26 15:03 小神你好 阅读( ...) 评论( ...) 编辑 收藏

转载于:https://www.cnblogs.com/oem01/p/3592004.html

### 什么是多态性? 多态性是面向对象编程中的核心概念之一,它允许不同的对象对相同的请求做出不同的响应。这种特性提高了代码的灵活性、可扩展性可维护性。多态性主要表现为两种形式:静态多态动态多态。静态多态是通过函数重载实现的,而动态多态则是通过虚函数实现的[^1]。 ### 虚函数的作用 虚函数是实现多态性的关键。当使用基类指针引用来访问派生类对象时,虚函数确保调用的是派生类中的实现,从而实现运行时多态性。这使得程序具有更高的可扩充性,增加了类的功能时也非常方便,甚至可以实现前人调用后人写的代码。多态性把操作细节留给类的设计者(专业人员)去完成,而让编程人员(类的使用者)只需做一些宏观性的工作,告诉系统做什么,不必考虑怎么做,简化了应用程序的编码工作[^2]。 ### 虚函数的工作原理 虚函数的底层原理涉及虚函数表(vtable)虚函数指针(vptr)。每个含有虚函数的类都有一个虚函数表,其中包含了该类所有虚函数的地址。每个对象都有一个指向其虚函数表的指针(vptr)。当通过基类指针引用调用虚函数时,程序会根据对象的实际类型找到对应的虚函数表,并调用相应的函数。这种方式确保了在运行时能够正确调用派生类的实现[^1]。 ### 虚函数的使用方法 在C++中,虚函数的声明非常简单,只需要在基类中的函数声明前加上`virtual`关键字即可。派生类可以选择性地重写这些虚函数,以提供特定的行为。以下是一个简单的示例: ```cpp #include <iostream> using namespace std; class Base { public: virtual void Fn() { cout << "在基类内" << endl; } }; class SubClass : public Base { public: void Fn() override { cout << "在派生类内" << endl; } }; void test(Base& b) { b.Fn(); } int main() { Base bc; SubClass sc; cout << "调用test(bc)\n"; test(bc); cout << "调用test(sc)\n"; test(sc); return 0; } ``` 在这个示例中,`Base`类中的`Fn`函数被声明为虚函数,`SubClass`类重写了这个函数。通过`test`函数传入`Base`类型的引用,无论传入的是`Base`对象还是`SubClass`对象,都能正确调用各自的`Fn`函数[^4]。 ### 虚函数与一般重载函数的区别 虚函数与一般的重载函数的主要区别在于调用时机的不同。虚函数的调用是在运行时决定的,而一般的重载函数是在编译时决定的。虚函数通过虚函数虚函数指针实现动态绑定,而一般的重载函数通过函数签名的不同实现静态绑定[^3]。 ### 虚析构函数 当一个类被设计为基类时,通常需要将其析构函数声明为虚函数。这样做的目的是确保在删除指向派生类对象的基类指针时,能够正确地调用派生类的析构函数,从而避免内存泄漏。虚析构函数的定义使用与普通虚函数类似,只需在析构函数前加上`virtual`关键字即可[^3]。 ### 应用实例 多态性在实际开发中有广泛的应用,例如在图形用户界面库中,可以通过多态性实现不同控件的统一处理。通过定义一个基类`Widget`,并在其中声明虚函数`draw`,不同的控件类如`Button`、`Label`等可以继承并重写`draw`函数,从而实现各自特定的绘制行为。这样,程序可以通过基类指针引用统一处理各种控件,提高了代码的通用性可维护性[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值