C++点点滴滴

来源:互联网 发布:涂鸦跳跃 java 编辑:程序博客网 时间:2024/06/05 22:31
对象作为参数传给函数,以及函数返回对象的问题

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; // Compositionpublic:  // 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++>>内容

原创粉丝点击