现在的位置: 首页 > 综合 > 正文

C++学习小结

2013年08月12日 ⁄ 综合 ⁄ 共 3890字 ⁄ 字号 评论关闭

一、构造和析构函数

C++在幕后为你写的的函数:一个拷贝构造函数,一个赋值运算符,一个析构函数,一对取址运算符。另外,如果你没有声明任何构造函数,它也将为你声明一个缺省构造函数。所有这些函数都是公有的。换句话说,如果你这么写:

class Empty{};

和你这么写是一样的:

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

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

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

深拷贝和浅拷贝:

默认拷贝构造函数均是浅拷贝。但是一个类可能拥有其它资源,如其构造函数分配了一个堆内存,析构函数释放了这个内存,则此时就需要进行深拷贝了,深拷贝不能依赖编译器实现。为需要动态分配内存的类声明一个拷贝构造函数和一个赋值操作符。

拷贝构造函数的调用:
1、当用类的一个对象去初始化该类的另一个对象时。
2、当对象作为函数的实参传递给函数的形参时。
3、当函数的返回值是类的对象,函数执行完成返回时。

在构造函数中调用另一个构造函数,会生成一个临时对象,并且立即释放。 
string c=a;只调用了拷贝构造函数。而string c; c=a;分别调用了构造函数和赋值函数。

构造函数和析构函数的注意点:
1、构造函数和析构函数不能有返回值
2、可以显式调用构造函数和析构函数
3、拷贝(复制)构造函数不能用值传递
4、不要在构造函数和析构函数中抛出异常和调用有异常抛出的函数,可能会有内存泄露!
5、确定基类有虚析构函数

二、static、const、友元与虚函数

1.静态成员使用static申明,在内存中永远只有一份实例(静态变量,类内声明,类外定义)
2.是类的对象所共有的
3.静态成员变量可以被成员函数访问,但静态成员函数只能访问静态成员变量
4.友元是为了一个普通函数直接访问一个类的保护甚至是私有成员的机制

虚函数:
在普通成员函数前面加 virtual 关键字
一个函数在基类申明一个virtual,那么在所有的派生类都是是virtual的
一个函数在基类为普通函数,在派生类定义为virtual的函数称为越位

抽象类:
具有纯虚函数的类就是抽象类
抽象类不能被实例化,所以抽象类只能以指针方式被应用
抽象类可以防止切片的发生
抽象类不产生虚表。

const对象与成员:
1.const对象只能访问const成员函数,而非const对象可以访问任意的成员函数,包括const成员函数.
2.const对象的成员是不可修改的,然而const对象通过指针维护的对象却是可以修改的.
3.const成员函数不可以修改对象的数据,不管对象是否具有const性质。
4.然而加上mutable修饰符的数据成员,对于任何情况下通过任何手段都可修改,此时的const成员函数是可以修改它的

三、设计与实现

C++面向对象编程中一条重要的规则是:公有继承意味着 "是一个" 。一定要牢牢记住这条规则。

C++有两种多态多态形式:
1、编译时刻多态,编译时刻多态依靠函数重载或者模板实现
2、运行时刻多态。运行时刻多态依靠需函数虚接口实现

引用的使用原则:
1.在可以用引用的情况下,不要用指针
2.引用可以作为“左值”
3.引用不允许为空,当存在对象为空时,必须使用指针。 引用指向一个空值,是非常有害的!
4.尽量用“传引用”而不用“传值”
5.必须返回一个对象时不要试图返回一个引用
6.千万不要返回局部对象的引用,也不要返回函数内部用new初始化的指针的引用

类中有const数据,必须要有构造函数对它初始化。
static const double a;       //静态double常量声明!
const double 类名::a=1.04;   //静态初始化!

T& operator[](int index); //传回数组的一个元素,可读,可写
const T& operator[](int index)const;  //传回数组的一个元素,可读,不可写

重载函数,区分是不是重载函数的标准:
(1)只能靠函数的参数来区分重载函数(类型、个数、缺省参数)
(2)不能靠函数的返回值来区分重载函数

四、C++与C的一些区别

C中struct和C++中struct的区别:
C++的struct可以当作class来用,区别是,class中的成员默认是private,而struct的成员默认为public。 
C中的struct只能是一些变量的集合体,可以封装数据却不可以隐藏数据,而且成员不可以是函数。 
C中的Struct是用户自定义数据类型(UDT),C++中的Struct是抽象数据类型(ADT),支持成员函数的定义。 

C++语言担保,如果p等于NULL,则delete p不作任何事情。
delete p 是一个两步的过程:调用析构函数,然后释放内存。
delete p调用的是operator delete(void*),而delete[] p调用的是operator delete[](void*)。

static 关键字至少有下列作用:   
(1)函数体内static变量的作用范围为该函数体,不同于auto变量,该变量的内存只被分配一次, 因此其值在下次调用时仍维持上次的值;   
(2)在模块内的static全局变量可以被模块内所用函数访问,但不能被模块外其它函数访问;   
(3)在模块内的static函数只可被这一模块内的其它函数调用,这个函数的使用范围被限制在声明它的模块内; 
(4)在类中的static成员变量属于整个类所拥有,对类的所有对象只有一份拷贝;   
(5)在类中的static成员函数属于整个类所拥有,这个函数不接收this指针,因而只能访问类的static成员变量。 

const 关键字至少有下列作用:   
(1)欲阻止一个变量被改变,可以使用const关键字。在定义该const变量时,通常需要对它进行初始化,因为以后就没有机会再去改变它了;
(2)对指针来说,可以指定指针本身为const,也可以指定指针所指的数据为 const,或二者同时指 定为const;
(3)在一个函数声明中,const可以修饰形参,表明它是一个输入参数,在函数内部不能改变其值;
(4)对于类的成员函数,若指定其为const类型,则表明其是一个常函数,不能修改类的成员变量;
(5)对于类的成员函数,有时候必须指定其返回值为const类型,以使得其返回值不为“左值”。

一个基类及其继承类的实现:

class Base
{
    public:
    Base(const char *s=NULL);
    Base(const Base& rth);
    Base & operator=(const Base & oth);
    virtual ~Base();
    private:
    char *m_data;
};
Base::Base(const char* s)
{
    if(s==NULL)
    {
        m_data=new char[1];
        m_data[0]='\0';
    }
    else
    {
        int length=strlen(s);
        m_data=new char[length+1];
        strcpy(m_data,s);
    }
}
Base::Base(const Base & oth)
{
    int len=strlen(oth.m_data);
    m_data=new char[len+1];
    strcpy(m_data,oth.m_data);
}
Base & Base::operator=(const Base & oth)
{
    if(this==&oth) return *this;
    delete []m_data;
    int len=strlen(oth.m_data);
    m_data=new char[len+1];
    strcpy(m_data,oth.m_data);
    return *this;
}
Base::~Base()
{
    delete[] m_data;
}

class Derived : public Base
{
    public:
    Derived(const char* s=NULL,int a=0);
    Derived(const Derived& oth);
    Derived& operator=(const Derived& oth);
    private:
    int m;
};
Derived::Derived(const char* s,int a):Base(s),m(a){ }
Derived::Derived(const Derived& oth):Base(oth),m(oth.m){ }
Derived& Derived::operator=(const Derived& oth)
{
    if(this==&oth) return *this;
    Base::operator=(oth);
    m=oth.m;
    return *this;
}

C++编译器不支持模板头文件和实现代码分离的编译

在分离式编译的环境下,编译器编译某一个.cpp文件时并不知道另一个.cpp文件的存在,也不会去查找(当遇到未决符号时它会寄希望于连接器)。这种模式在没有模板的情况下运行良好,但遇到模板时就不行,因为模板仅在需要的时候才会具现化出来,所以,当编译器只看到模板的声明时,它不能具现化该模板,只能创建一个具有外部连接的符号并期待连接器能够将符号的地址决议出来。然而当实现该模板的.cpp文件中没有用到模板的具现体时,编译器懒得去具现,所以,整个工程的.obj中就找不到一行模板具现体的二进制代码,于是连接器也傻了!

抱歉!评论已关闭.