条款45: 弄清C++在幕后为你所写、所调用的函数

当C++编译器通过它的时候。如果你没有声明下列函数,体贴的编译器会声明它自己的版本。这些函数是:一个拷贝构造函数,一个赋值运算符,一个析构函数,一对取址运算符。另外,如果你没有声明任何构造函数,它也将为你声明一个缺省构造函数。所有这些函数都是公有的。换句话说,如果你这么写:

class Empty{};

和你这么写是一样的:

class Empty {
public:
  Empty();                        // 缺省构造函数
  Empty(const Empty& rhs);        // 拷贝构造函数

  ~Empty();                       // 析构函数 ---- 是否
                                  // 为虚函数看下文说明
  Empty&
  operator=(const Empty& rhs);    // 赋值运算符

  Empty* operator&();             // 取址运算符
  const Empty* operator&() const;
};

假设编译器为你写了函数,这些函数又做些什么呢?是这样的,缺省构造函数和析构函数实际上什么也不做,它们只是让你能够创建和销毁类的对象。注意,生成的析构函数一般是非虚拟的(参见条款14),除非它所在的类是从一个声明了虚析构函数的基类继承而来。缺省取址运算符只是返回对象的地址。这些函数实际上就如同下面所定义的那样:

inline Empty::Empty() {}

inline Empty::~Empty() {}

inline Empty * Empty::operator&() { return this; }

inline const Empty * Empty::operator&() const
{ return this; }

至于拷贝构造函数和赋值运算符,官方的规则是:缺省拷贝构造函数(赋值运算符)对类的非静态数据成员进行 "以成员为单位的" 逐一拷贝构造(赋值)。即,如果m是类C中类型为T的非静态数据成员,并且C没有声明拷贝构造函数(赋值运算符),m将会通过类型T的拷贝构造函数(赋值运算符)被拷贝构造(赋值)---- 如果T有拷贝构造函数(赋值运算符)的话。如果没有,规则递归应用到m的数据成员,直至找到一个拷贝构造函数(赋值运算符)或固定类型(例如,int,double,指针,等)为止。默认情况下,固定类型的对象拷贝构造(赋值)时是从源对象到目标对象的 "逐位" 拷贝。对于从别的类继承而来的类来说,这条规则适用于继承层次结构中的每一层,所以,用户自定义的构造函数和赋值运算符无论在哪一层被声明,都会被调用。

class NamedObject
{
public:
    NamedObject(string &name, const int &value)
        :nameValue(name), objectValue(value){}
private:
    string &nameValue;
    const int objectValue;
};

void main()
{
    string newDog("persephone");
    string oldDog("satch");

    NamedObject p(newDog, 2);
    NamedObject s(oldDog, 29);

    p = s;
}
时间: 2024-10-12 04:50:29

条款45: 弄清C++在幕后为你所写、所调用的函数的相关文章

条款09:绝不在构造和析构过程中调用virtual函数

在base构造期间virtual函数不是virtual函数,因为构造函数首先从base构造函数开始执行,执行的时候继承类的对象并没有也就无从调用其成员函数,用以下这种方式能解决问题: 上面的做法,在要对继承类使用构造函数的时候通过参数传递给base构造函数. 注意:

条款9:绝不要在构造以及析构函数中调用虚函数

在构造以及析构函数期间不要调用virtual函数,因为这类调用从不下降到derived class中.例如说下面这个例子: 1 class Transaction{ 2 public: 3 Transaction(); 4 virtual void logTransactions()s const = 0; 5 //... 6 }; 7 Transaction::Transaction() 8 { 9 //... 10 logTransaction(); 11 } 12 class BuyTra

条款9:不要在构造和析构过程中调用virtual函数

如下是一个股票交易的例子: 1 class Transaction // 交易的基类 2 { 3 public: 4 Transaction(); 5 virtual void logTransaction() const = 0; // 用于记录交易日志 6 }; 7 Transaction::Transaction() 8 { 9 logTransaction(); // 调用虚函数 10 } 11 12 class BuyTransaction : public Transaction /

effective c++ 条款09:绝不在构造和析构过程中调用virtual函数

记住:在构造和析构期间不要调用virtual函数,因为这类调用从不下降至derived class. class Transaction { //所有交易的base class public: Transaction(); virtual void logTransaction() const = 0; //做出一份因类型不同而不同的log }; Transaction::Transaction() { ... logTransaction(); } class BuyTransaction:

Effective C++ 条款九、十 绝不在构造和析构过程中调用virtual函数|令operator=返回一个reference to *this

  1.当在一个子类当中调用构造函数,其父类构造函数肯定先被调用.如果此时父类构造函数中有一个virtual函数,子类当中也有,肯定执行父类当中的virtual函数,而此时子类当中的成员变量并未被初始化,所以无法调用子类与之对应的函数.即为指向虚函数表的指针vptr没被初始化又怎么去调用派生类的virtual函数呢?析构函数也相同,派生类先于基类被析构,又如何去找派生类相应的虚函数? 2.做法:将子类的某个函数改为non-virtual,然后在子类构造函数中传递参数给父类函数.然后父类的构造函数

Effective C++_笔记_条款09_绝不在构造和析构过程中调用virtual函数

(整理自Effctive C++,转载请注明.整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/) 为方便采用书上的例子,先提出问题,在说解决方案. 1 问题 1: class Transaction{ 2: public: 3: Transaction(); 4: virtual void LogTransaction() const = 0 ; 5: ... 6: }; 7:  8: Transaction::Transaction() //Base cl

Effective C++条款45 附加代码

本节是对上一篇博客的附加代码,基本的45条款思想已经实现. #include<iostream> using namespace std; template<typename T> class SharedPtr { public: template<typename U> SharedPtr(const SharedPtr<U>&u) :ptr(u.get()) { count++; } SharedPtr(T*ptr_):ptr(ptr_){}

Effective C++ 条款45 运用成员函数模板接受所有兼容类型

1. "智能指针"是行为像指针的对象,但它们能提供指针没有的功能:shared_ptr,weak_ptr,auto_ptr(见条款13)实现对堆内存的自动管理,STL的迭代器实现对整个容器的遍历等. 真正的指针的优势在于支持继承层次中派生类指针向基类指针的转换(当然标准库shared_ptr,weak_ptr,auto_ptr等已实现). 2. 由于同一template的不同具现体之间没有直接联系,也就是说对于自定义的智能指针(假设名为SmartPtr),如果不额外采取手段支持基层层次

Effective C++ 条款45

本节条款的题目是运用成员模板接受所有兼容类型 作者阐述自己的观点是通过智能指针的例子. 在学习本节条款之前我们要先明白关于隐式转化的问题 如下代码: #include<iostream> using namespace std; class A { public: explicit A(int i):a(i){}; A(const A&obj):a(obj.a) { } private: int a; }; int main() { int value =0; A a = value;