《C++沉思录》---笔记

1.序幕

  • 下面这段代码放在C实现是很麻烦的:
calss Trace{
public:
    Trace(){noise = 0;f = stdout;}
    Trace(FILE *ff){noise = 0;f == ff;}
    void print(char *s){
        if(noise)fprintf(f,"%s",s);
    }
    void on(){noise = 1;}
    void off(){noise = 0;}
private:
    int noise;
    FILE *f;
};
  • ??? 是什么让C++对系统的改变变得如此容易:关键在于,一项计算的状态作为对象的一部分是显示可用的,而不是隐藏在幕后的东西。

第一篇—动机

第一章 我为什么用C++

  • “我被C++吸引住,很大长度上源于数据的抽象而不是面向对象编程…”

第二章 我为什么用C++工作

。。。


第二篇—类和继承

第四章 类设计者的核查表

  • 1.你的类需要一个构造函数吗?
  • 2.你数据成员是私有的吗?
  • 3.你的类需要一个无参构造函数吗?
    • 如果一个类需要一个显示构造函数,那生成该类对象的数组是非法的,
  • 4.是不是每个构造函数初始化所有的数据成员?
    • 构造函数的用途是一种明确定义的状态来设置对象。对象的状态由数据成员进行反映。为此,每个构造函数都要负责为所有的数据成员设置经过明确顶一顶额值,如果没有做到这一点,会比较容易出错。
  • 5.类需要析构函数吗?
    • 只需要考虑该类是否分配了资源,而这些资源又不会由成员函数自动释放
  • 6.类需要一个虚析构函数吗?
    • 绝不会用作基类的类是不需要析构函数的:任何虚函数只有在继承的情况下才有用。考虑下面这段代码:
class B{
public:
    B(){printf("B");}
    ~B(){               //①
    //virtual ~B(){     //②
        printf("~B");}
};
class D:public B{
public:
    D(){printf("D");}
    ~D(){printf("~D");}
};
void main(int argc,char *argv[])
{
    //D* pp=new B;  //语法错误
    D* dp=new D;
    delete dp;
    printf("\n");
    B* bp=new D;
    delete bp;
}

这时候的输出是:

BD~D~B
BD~B

这个明显不是我们想要的结果(new D,那么应该调用D的析构,这里调用的是B的析构),解决的办法就是把B类的析构函数写成虚函数。

  • 7.你的类需要复制构造函数吗?
    • 关键在于复制该类的对象是否就相当于复制其数据成员和基类对象,通常在构造函数内分配了资源的(含有指针)需要一个显示的复制构造函数。—>可能造成一个指针被释放两次
  • 8.你的类需要一个赋值操作符吗?
    • 通常需要赋值构造函数就需要赋值操作符
  • 9.你的赋值操作符能正确的将对象赋给对象本身吗?
    • 这个在《剑指offer》中也提到了,下面是一个推荐的做法:
String& String::operator=(const String& s){
    char *newdata = new char[strlen(s.data)+1];
    strcpy(newdata,s.data);
    delete [] data;
    data = newdata;
    return this;
}
  • 10.你的类需要关系操作符吗?
    • 只要用户想创建你的类型的有序集合,你就必须提供关系操作符
  • 11.删除数组时你用了 delete[] 了吗?
    • 先看下面这段代码:
    char *p3=(char *)malloc(10);
    delete p3;
    
    char p1[]="acbdefghijk";
    char *p2=p1;
    printf("size p1=%d,size p2=%d\n",sizeof(p1),sizeof(p2));

C程序员希望使用malloc()分配内存,然后返回给C++函数,并希望能用delete来释放那些内存,为此C++必须利用原来的malloc直接实现new,所以在C++释放内存时,不一定要清楚数组的大小,但要求被告知要删除的是不是数组(是的话可能会提供另一个地方来存储长度)。尽管有些C++实现只在数组中的对象有特殊的析构函数时才要求这样做,但是在删除任何类型的数组时使用[]语法任然是一种好习惯

  • 12.记得在复制构造函数和赋值操作符的参数类型中加上const
    • 赋值构造函数应该是像:X::X(const X&),毕竟复制构造不会改变原来的的对象,同样的道理也适用于赋值:X::operator=(const X&)
  • 13.如果函数有引用参数,它们应该是const引用吗?
    • 只有当函数想改变参数时,才不应该是。比如总应该这样写:
Complex operator+(const Complex& x,const Complex& y);
  • 14.记得适当的声明成员函数为const的了吗?
    • 如果确信一个成员函数不用修改它的对象,就可以把它声明为const
class Vector{
public:
    //int length() const{
    int length(){
        return len;
    }
    int length(int length){
        len = length;
    }
private:
    int len;
};
int padded_length(const Vector& v,int n){
    int k=v.length();   // oops!
    return k>n?k:n;
}

除非对length()的声明加了const,否则标记了oops的行编译通不过

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值