cpp备忘摘录

const关键字

基本用法

int a1=3;   ///non-const data
const int a2=a1;    ///const data
int const a2=a1;
const int * a3 = &a1;   ///const data,non-const pointer
int * const a4 = &a1;   ///non-const data,const pointer

int const * const a5 = &a1;   ///const data,const pointer
const int * const a6 = &a1;   ///const data,const pointer

1.const位于*左侧,指针所指数据是常量,不能通过解引用修改该数据;
2.const位于*右侧,指针本身是常量,不能指向其他内存地址;
3.两个const,*左右各一个,表示指针和指针所指数据都不能修改。

其他

  • 用const修饰的变量必须在声明时进行初始化(用来修饰函数的形参除外
  • C语言和C++中的const有很大区别。在C语言中用const修饰的变量仍然是一个变量;而在C++中用const修饰过后,就变成常量了。

static,const,static const , const static成员初始化

http://blog.sina.cn/dpool/blog/s/blog_446b43c10100d8s7.html

四种cast

http://blog.sina.com.cn/s/blog_4a84e45b0100f57m.html


隐式转换与explicit

隐式转换的风险一般存在于自定义的类构造函数中。
按照默认规定,只有一个参数的构造函数也定义了一个隐式转换,将该构造函数对应数据类型的数据转换为该类对象。

class String
{
public:
    String ( int n ); //本意是预先分配n个字节给字符串
    String ( const char* p ); // 用C风格的字符串p作为初始化值

    //…
}
//String s4 = 10; //编译通过,也是分配10个字节的空字符串
//String s5 = ‘a’; //编译通过,分配int(‘a’)个字节的空字符串

C++中提供了explicit关键字,在构造函数声明的时候加上explicit关键字,能够禁止隐式转换。

class Test
{
    explicit Test(int a);
    ……
}

类构造函数

复制构造函数(拷贝构造函数)

复制构造函数参数为类对象本身的引用,用于根据一个已存在的对象复制出一个新的该类的对象。若没有显示的写复制构造函数,系统会默认创建一个复制构造函数,但当类中有指针成员时,由系统默认创建该复制构造函数会存在风险

等号运算符重载

这个类似复制构造函数,将=右边的本类对象的值复制给等号左边的对象,它不属于构造函数,等号左右两边的对象必须已经被创建。若没有显示的写=运算符重载,则系统也会创建一个默认的=运算符重载,只做一些基本的拷贝工作

Complex &operator=( const Complex &rhs )
{
    // 首先检测等号右边的是否就是左边的对象本,若是本对象本身,则直接返回
    if ( this == &rhs ) 
    {
        return *this;
    }

    // 复制等号右边的成员到左边的对象中
    this->m_real = rhs.m_real;
    this->m_imag = rhs.m_imag;
    // 把等号左边的对象再次传出
    // 目的是为了支持连等 eg:    a=b=c 系统首先运行 b=c
    // 然后运行 a= ( b=c的返回值,这里应该是复制c值后的b对象)    
    return *this;
}

深拷贝浅拷贝

没有自定义复制构造函数,则系统会创建默认的复制构造函数,但系统创建的默认复制构造函数只会执行“浅拷贝”,即将被拷贝对象的数据成员的值一一赋值给新创建的对象,若该类的数据成员中有指针成员,则会使得新的对象的指针所指向的地址与被拷贝对象的指针所指向的地址相同,delete该指针时则会导致两次重复delete而出错。

Person(Person & chs);
{
    // 用运算符new为新对象的指针数据成员分配空间
    m_pName=new char[strlen(p.m_pName)+ 1];

    if(m_pName)         
    {
        // 复制内容
        strcpy(m_pName ,chs.m_pName);
    }
    // 则新创建的对象的m_pName与原对象chs的m_pName不再指向同一地址了
}

类的static函数

  • 对象名.静态函数()
  • 类名::静态函数() 是可以的
  • 类名.静态函数() 是不可以的

构造/析构函数

子类无法继承父类的构造函数和析构函数。
没有显示调用的情况下,会自动调用父类的构造/析构函数。
1)子类先调用基类的构造函数然后再调用自己的构造函数
2)子类是调用自身的析构函数再调用基类的析构函数
显示调用构造函数形式为:

子类构造函数名(子类总参数列表):父类构造函数名(参数列表)
{
    子类新增初始化语句;
}

虚函数与构造/析构函数

  • 虚函数是为了允许用基类指针调用子类的函数。若基类中没用virtual定义,则不管哪个子类,调用的都是基类的成员函数。
  • 虚函数必须实现,如果不实现,编译器将报错
  • 定义一个函数为纯虚函数,才代表函数没有被实现。
  • 虚函数是针对对象的,不是针对类的。有了实际对象,虚函数才有意义。

  • 在有动态分配堆上内存的时候,析构函数必须是虚函数,但没有必要是纯虚的。

2) 构造函数不能是虚函数,因为构造子类时本身也是调用的子类构造函数,然后子类构造函数会调用基类构造函数,所以虚构造函数的存在是没有意义的。只有在构造完成后,对象才能成为一个类的名符其实的实例。
3) 静态成员函数和内联函数也不能是虚函数。
3) 析构函数可以是虚函数,而且,在一个复杂类结构中,这往往是必须的。
4) 将一个函数定义为纯虚函数,实际上是将这个类定义为抽象类,不能实例化对象。
6) 析构函数可以是纯虚的,但纯虚析构函数必须有定义体,因为析构函数的调用是在子类中隐含的。
8) 派生类的override虚函数定义必须和父类完全一致。除了一个特例,如果父类中返回值是一个指针或引用,子类override时可以返回这个指针(或引用)的派生。例如,在上面的例子中,在Base中定义了 virtual Base* clone(); 在Derived中可以定义为 virtual Derived* clone()。可以看到,这种放松对于Clone模式是非常有用的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值