C++点点滴滴

对象作为参数传给函数,以及函数返回对象的问题

1, 当对象作为参数直接传给函数时(passing object by value),作为该对象的一个拷贝,一个新的对象会产生。
但是需要注意的是:
该新的对象被自动创建的时候, 构造函数(constructor)并不被调用,而是 复制构造函数(copy constructor)被调用;因为构造函数是初始化一个对象,而作为传入函数的参数,是现有对象的一个拷贝。
当函数结束的时候,为了参数而新创建的对象的生命周期也会结束,因此,这个时候,对象的 析构函数(destructor)会被调用。

2, 当函数返回一个对象的时候,需要注意的是, 如果该返回值不被明确地赋值给一个对象的话,一个临时的对象会被自动创建,用于其他可能的计算;同样的,对象的返回 (无论是否临时对象),对象的 复制构造函数会被调用,而不是构造函数;当临时对象完成使命(返回 has been returned)后,对象的 析构函数(destructor)会被调用。

因此,对象作为参数传给函数,以及函数返回对象的时候,特别需要注意对象的成员中有指针的情况。
 
关于复制构造函数(copy constructor)

当一个变量通过一个现有的对象被创建的时候,复制构造函数会被调用。

存在于下面三种情况(注意,赋值操作的时候,并不会被调用):
1,声明一个变量的时候,同时初始化该变量
---------------------------------------------------------------------------------
Person q("Mickey");      // 构造函数被调用
Person r(p);                  // 复制构造函数被调用
Person p = q;                // 复制构造函数被调用
 p = q;                          //  这是一个赋值操作, 构造函数复制构造函数被调用
---------------------------------------------------------------------------------
2, 当对象作为参数直接传给函数时(passing object by value)
3, 当函数返回一个对象的时候

参考: http://www.fredosaurus.com/notes-cpp/oop-condestructors/copyconstructors.html  

● 关于 运算符重载(operator overloading)

运算符重载可以通过 成员函数(member functions)友好函数(friend functions)实现。
但是有以下的限制:
1, 不能改变运算符的优先级
2, 不能创建新的运算符
3, 不能重载 :: sizeof ?: . **
      (Thinking in C++:   .    .*   **)

4, 重载+并不意味着同时重载了+=,其他-=等也是同样
5, 重载 =,[],-> ,() 运算符的时候,只能通过成员函数实现, 从而强制使得左操作数类型是所定义的类
6, ++ 和 -- 的重载需要特殊的处理 (a++/a--和++a/--a的区别)
7, = 的重载需要特殊的考虑 (自我判断,指针的释放和分配)

Thinking in C++:   
Murray 对于操作符重载是否使用成员函数有如下建议
:
操作符建议
所有的一元符号成员函数
= ( ) [ ] –> –>*必须是成员函数
+= –= /= *= ^=
&= |= %= >>= <<=
成员函数
所有的二元符号非成员函数

● 关于函数隐藏
子类可以通过改变返回值或者参数来隐藏父类的函数,但如果该函数是虚拟函数的话,则只能通过改变参数而不能通过改变返回值来隐藏该函数,因为相同参数的虚拟函数只能覆盖而不能隐藏,而覆盖只能返回相同的返回值类型(或者该类型的派生类)。

● 关于继承
1,构造函数,复制构造函数,析构函数,赋值(=)操作符号函数并不会自动被继承,而是被综合(synthesized)
2,如果子类明确定义了复制构造函数/赋值操作符号函数,必须明确调用父类的相应的复制构造函数/赋值操作符号函数,否则父类的缺省构造函数会被调用。
3,赋值操作符号函数只综合相同类型对象的赋值。

From <<Thinking in C++>>

----------------------------------------------------------------------------------------------


  
  
//:! :CopyRight.txt
(c) 1995-2004 MindView, Inc.  All rights reserved.
//: C14:SynthesizedFunctions.cpp
// Functions that are synthesized by the compiler
#include <iostream>
using namespace std;

class GameBoard {
public:
  GameBoard() { cout << "GameBoard()/n"; }
  GameBoard(const GameBoard&) { 
    cout << "GameBoard(const GameBoard&)/n"; 
  }
  GameBoard& operator=(const GameBoard&) {
    cout << "GameBoard::operator=()/n";
    return *this;
  }
  ~GameBoard() { cout << "~GameBoard()/n"; }
};

class Game {
  GameBoard gb; // Composition
public:
  // Default GameBoard constructor called:
  Game() { cout << "Game()/n"; }
  // You must explicitly call the GameBoard
  // copy-constructor or the default constructor
  // is automatically called instead:
  Game(const Game& g) : gb(g.gb) { 
    cout << "Game(const Game&)/n"; 
  }
  Game(int) { cout << "Game(int)/n"; }
  Game& operator=(const Game& g) {
    // You must explicitly call the GameBoard
    // assignment operator or no assignment at 
    // all happens for gb!
    gb = g.gb;
    cout << "Game::operator=()/n";
    return *this;
  }
  class Other {}; // Nested class
  // Automatic type conversion:
  operator Other() const {
    cout << "Game::operator Other()/n";
    return Other();
  }
  ~Game() { cout << "~Game()/n"; }
};

class Chess : public Game {};

void f(Game::Other) {}

class Checkers : public Game {
public:
  // Default base-class constructor called:
  Checkers() { cout << "Checkers()/n"; }
  // You must explicitly call the base-class
  // copy constructor or the default constructor
  // will be automatically called instead:
  Checkers(const Checkers& c) : Game(c) {
    cout << "Checkers(const Checkers& c)/n";
  }
  Checkers& operator=(const Checkers& c) {
    // You must explicitly call the base-class
    // version of operator=() or no base-class
    // assignment will happen:
    Game::operator=(c);
    cout << "Checkers::operator=()/n";
    return *this;
  }
};

int main() {
  Chess d1;  // Default constructor
  Chess d2(d1); // Copy-constructor
//! Chess d3(1); // Error: no int constructor
  d1 = d2; // Operator= synthesized
  f(d1); // Type-conversion IS inherited
  Game::Other go;
//!  d1 = go; // Operator= not synthesized 
           // for differing types
  Checkers c1, c2(c1);
  c1 = c2;
} ///:~

--------------------------------------------------------------
GameBoard()
Game()
GameBoard(const GameBoard&)
Game(const Game&)
GameBoard::operator=()
Game::operator=()
Game::operator Other()
GameBoard()
Game()
Checkers()
GameBoard(const GameBoard&)
Game(const Game&)
Checkers(const Checkers& c)
GameBoard::operator=()
Game::operator=()
Checkers::operator=()
~Game()
~GameBoard()
~Game()
~GameBoard()
~Game()
~GameBoard()
~Game()
~GameBoard()
--------------------------------------------------------------


● 关于异常
1,当一个异常在所有的层次都不被捕获的时候,terminate()会被调用
2,当一个局部变量的析构函数中抛出异常的时候,terminate()会被调用;当一个全局变量或者static变量的构造函数或者析构函数种抛出异常的时候,terminate()会被调用。
3,当一个对象在构造函数中抛出异常的时候,它的析构函数不会被调用。


参考资料
http://www.fredosaurus.com/notes-cpp/
<<Thinking in C++>> 2ed   2000 by Bruce Eckel 

Jady Leung 2004年9月30日创建
                  2005年2月28日更新,增加<<Thinking in C++>>内容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值