对象切割 - 常量引用传递

本文探讨了C++中对象传递的方式及其对性能的影响,包括值传递与引用传递的区别,并通过实例说明了如何利用指针和引用实现多态。


看一个简单的例子:

#include <iostream>
using namespace std;

class Base
{
private:
        string name;
        string hobby;
 string title;
};

void fun(Base a)
{
}

int main()
{
      Base a;
      fun(a);
      return 0;
}


在调用fun函数时,会有形参的拷贝,会调用Base的构造函数,由于name、hobby和title都是string对象,所以会有构造。也就是4次构造,对应的有4次析构,消耗很大,通过引用传递可以有效地避免


#include <iostream>
using namespace std;

class Base
{
private:
        string name;
        string hobby;
        string title;
};

void fun(Base &a) //引用,不会有临时对象拷贝
{
}

int main()
{
      Base a;
      fun(a);
      return 0;
}

对象切割

  当把一个派生类的对象赋给一个基类的对象时,会发生对象切割(基类对象强制转换派生类对象也会发生)

例如

   

class Base
{
public:
	virtual void fun()
	{
		cout << "Base fun() is Called." << endl;
	}
};

class Derived:public Base
{
public:
	void fun()
	{
		cout << "Derived fun() is called." << endl;
	}
};

void fun1(Base b)
{
	b.fun();
}

void fun2(Base *b)
{
	b->fun();
}

void fun3(Base &b)
{
	b.fun();
}

int main()
{
	Derived d;
	fun1(d);
	fun2(&d);
	fun3(d);
	system("pause");
	return 0;
}


运行结果为:



可以看出,指针和地址传递可以实现虚函数的多态功能,在fun1(Base b)中, 传递Derived对象时发生了对象的切割,而对象的切割不会发生多态,所以调用Base当中对应的函数。

总结:多态的实现是通过指针和引用;而对象的转换只会造成对象切割,不能实现多态




<think>好的,我现在需要解释C++中形参写常量引用和值传递的区别。用户之前已经问过Lambda表达式,现在这个问题可能是在参数传递方式上的深入。首先,我应该回顾一下这两种传递方式的基本概念。 值传递(Pass by Value)是将实际参数的值复制到函数形参中,函数内操作的是副本,不会影响原始数据。而常量引用(Const Reference)则是将形参作为原变量的别名,但通过const限定符保证不会修改原数据。 接下来,我需要比较两者的区别,包括性能、安全性、使用场景等方面。比如,值传递适用于小型数据或需要修改副本的情况,而常量引用适合传递大型结构体或类对象以避免复制开销,同时防止意外修改。 可能需要注意的细节包括:值传递的拷贝构造函数调用成本,常量引用如何避免不必要的复制,以及const正确性的重要性。此外,用户可能想知道何时选择哪种方式,比如在函数不修改参数且参数较大时用常量引用,而需要修改副本或参数较小时用值传递。 还要考虑例外情况,比如内置类型(如int)通常用值传递更高效,而自定义类型用常量引用更好。可能用户会混淆引用传递和指针传递的区别,但这里问题明确是常量引用和值传递,所以不需要涉及指针。 需要确保语言准确,避免错误。例如,强调常量引用不能修改原数据,而值传递的修改不影响原变量。此外,可能举例子说明两种情况下的代码差异,以及各自的优缺点。 最后,总结两者的适用场景,帮助用户根据具体情况做出选择。可能还要提到C++11之后的移动语义对参数传递的影响,但用户的问题可能更关注基础,所以简要提及即可。</think>在 C++ 中,**值传递**和**常量引用传递**是两种参数传递方式,核心区别在于 **内存操作方式** 和 **性能开销**。以下是详细对比: --- ### 一、值传递(Pass by Value) #### 语法: ```cpp void func(int param) { ... } // 参数直接声明为类型 ``` #### 核心特性: 1. **复制行为**: 调用函数时,实参的值会被**复制**到形参(产生独立副本)。 2. **安全性**: 函数内对形参的修改**不影响实参**(副本隔离)。 3. **性能开销**: - **适合小型数据**(如 `int`, `char`) - **不适用于大型对象**(如结构体、类实例),频繁复制会导致性能损耗(触发拷贝构造函数) #### 示例: ```cpp void modify(int x) { x = 42; // 修改副本,不影响实参 } int main() { int a = 10; modify(a); std::cout << a; // 输出 10(原值未变) } ``` --- ### 二、常量引用传递(Pass by Const Reference) #### 语法: ```cpp void func(const int& param) { ... } // 参数声明为 const 引用 ``` #### 核心特性: 1. **无复制行为**: 形参是实参的**别名**(直接操作原数据,无拷贝开销)。 2. **安全性**: `const` 确保函数内**无法修改实参**(编译器强制检查)。 3. **性能优势**: - **适合大型对象**(如 `std::vector`, 自定义类),避免拷贝构造和析构开销 - 即使对小型数据(如 `int`),编译器可能优化为直接操作,无性能损失 #### 示例: ```cpp void readData(const std::vector<int>& data) { // data.push_back(1); // 错误!const 引用禁止修改原数据 for (auto num : data) { ... } // 只读操作,高效且安全 } int main() { std::vector<int> vec{1, 2, 3}; readData(vec); // 无拷贝,直接传递对象 } ``` --- ### 三、关键对比表 | **特性** | **值传递** | **常量引用传递** | |------------------------|-------------------------------|-------------------------------| | 内存操作方式 | 创建实参的独立副本 | 直接操作原数据(无副本) | | 对原数据的影响 | 完全隔离(修改不影响原数据) | 无法修改原数据(`const` 限制) | | 性能开销 | 高(大型对象频繁拷贝) | 低(无拷贝) | | 适用场景 | 小型数据、需要修改副本 | 大型对象、只读访问 | | 语法示例 | `void func(int param)` | `void func(const T& param)` | --- ### 四、选择原则 1. **优先常量引用**: - 传递自定义类、结构体或容器(如 `std::string`, `std::vector`) - 函数不需要修改参数,且需避免拷贝开销 2. **使用值传递**: - 内置类型(`int`, `double` 等)或简单枚举 - 需要修改形参副本(如 `void increment(int x) { x++; }`) 3. **例外情况**: - C++11 后可用**移动语义**(如 `void func(T&& param)`)优化大型对象传递 - 需要修改原数据时,使用**非 const 引用**(但需谨慎避免意外修改) --- ### 五、典型错误示例 ```cpp // 错误:试图通过常量引用修改原数据(编译失败) void badFunc(const int& x) { x = 10; // 错误!x 是 const 引用 } // 正确:若需修改副本,使用值传递 void goodFunc(int x) { x = 10; // 修改副本,不影响原数据 } ``` --- 通过合理选择参数传递方式,可显著提升代码性能和安全性。**常量引用传递**是优化大型对象处理的利器,而**值传递**在简单场景中更直观高效。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值