概述
0、通篇示例代码
class Person{
public:
Person();
virtual ~Person();
void Speak(){std::cout << name;}
...
private:
std::string name;
...
};
class Student: public Person{
public:
Student();
~Student();
void Speak(){std::cout << name;}
...
private:
std::string name;
...
}
1、有关值传递的过程中构造与析构过程
现有以下代码:
bool validateStudent(Student s);
Student Jack;
bool JackIsOk = validateStudent(Jack);
以上函数validateStudent
需要一个Student的实参(值传递),并返回它是否有效。
在函数被调用时,以Jack为蓝本将s初始化。且同样的在函数返回时,s会被销毁。
但是在整个过程中,Student中有一个string对象,每次构造一个Student对象也就会构造1个string对象。此外Student对象继承Person对象,所以每次构造Student对象也必须构造出一个Person对象,一个Person又有一个String对象。最终结果是,以值传递方式传递一个Student对象会导致调用一次Student copy构造函数、一次Person copy构造函数、两次String copy构造函数。因此,以值传递方式传递一个Student对象,总的成本是“4次构造函数和4次析构函数”。
解决办法:
bool validateStudent(const Student& s);
采用引用传递方法非常高效:没有任何构造函数或析构函数被调用,因为没有任何新对象被创建。修订后的const是重要的。原来通过值传递时,接收的是一个Student参数,因此调用者知道他们受到保护,validateStudent只能对其副本做修改。现在以引用方式传递,将其生命为const是必要的,因为需要保证函数不会改变传入的Student。
2、可能存在的对象切割(slicing)问题
现有以下代码:
void smoebodyspeak(Person p)
{
p.Speak();
}
int main()
{
Student rose;
somebodyspeak(rose);
}
很明显以上代码是以值传递方式将对象传递到somebodyspeak
中,但参数p会被构造成一个Person对象,从而造成rose"之所以是Student对象"的所有特化信息被切除。somebodyspeak
只会将传递过来的对象看作是Person对象,因为他的类型就是Person。因此在somebodyspeak
内调用的总是Person::Speak
,绝不会是Student::Speak
。
解决办法:
void smoebodyspeak(const Person& p)
{
p.Speak();
}
通过引用传递就会实现传进来的是什么类型,p就会表现出那种类型。
其实引用传递,往往是以指针实现出来,因此引用传递通常意味着真正传递的是指针。
注意:
1、尽量以引用传递代替值传递。前者通常比较高效,并且可以避免切割问题。
2、以上规则并不使用与内置类型,以及STL的迭代器和函数对象。对他们而言往往是值传递比较适当。
[1]有关书籍:Effective C++中文版(第三版)–Scott Meyers(著)与侯捷(译)
最后
以上就是无语西装为你收集整理的有关值传递可能产生的问题与解决(C++)的全部内容,希望文章能够帮你解决有关值传递可能产生的问题与解决(C++)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复