[读书笔记]第二次看C++ primer

4.2.4指针的使用
指针+整数其实是地址+sizeof(type),其实就是下一个对象的首地址。而不是简单的加上整数个字节。
普遍的const int *p;指向const对象,不能通过指针修改对象,但可以修改指针指向其他对象。
少见的 int *const p=&a;const常量指针,指针地址不能修改,必须初始化(跟普通const变量性质一样)。但可以通过指针修改对象内容。
区分这两种指针主要看const在*前还是后。正常的是在*左面。
 

7.8重载函数

只有在同一作用于声明的函数才会构成重载。如果在一个作用于里面声明一个函数名,将会屏蔽外层的同名函数。 (声明一个与外层函数名相同的变量也会有屏蔽作用)
 
重载++时,operator++(int)使用int来代表重载后递增a++,operator++()表示++a
 
如父类的构造函数被重写为带有才参数时,子类的成员初始化列表必须显式调用父类构造函数,否则编译出错。
//Base的构造函数是Base(int m);
class Derived:public Base
{
    Derived():Base(3){} 
};
 
自增符号重载:区分前置后置
class A
{
public:
    int val;
    void operator++(){//没有int参数,标志此函数为前置函数
        val++;
    }
    A operator++(int){//必须返回值而非返回引用,因为tmp是局部临时变量
        A tmp=(*this);//int参数是用于标记此函数是后置函数
        val+=1;
        return tmp;
    }
};

void operator++(A& a,int){}//如非成员函数,则第二个参数是int代表是后置符号

 

12.1类的声明与定义
1、使用初始化列表和使用构造函数体初始化的区别。
一、const成员只能被初始化不能被赋值,因此一定要用初始化列表。二、当有带有参数初始化的类作为本类的成员时,因为缺乏默认构造函数,作为本类的成员缺不能初始化,因此也必须使用初始化列表。
而且,使用初始化列表在特定情况会效率更高(否则会先调用一次默认构造函数,再进行一次赋值)。
 
友元可以访问私有成员。可定义友元类和友元函数派生类用户代码不可以访问基类的私有成员,但可以访问派生类对象的保护成员
派生类用户代码可以访问自己这个派生类的其他对象的保护成员,但不可以访问基类对象的保护成员。P476
总结:子类之间的protect相当于public,子类遇到父类的protect就相当于遇见private(不同的是连子类内部都不可以访问从父类继承下来的私有成员)
class classfather
{
    private:
    int pri;
    protect:
    int pro; 
};
void classson::fun(classson &son,classfather &father)
{
    int k=pro;//OK 访问自己的保护成员
    k=son.pro;//OK 访问其他子类对象的保护成员
    k=father.pro;//ERROR 类的外部,不能访问保护成员。
    k=this->pri;//ERRO 不可以访问自己的父类私有成员
}
 
15.1面向对象的概述
通过定义基类的成员函数为虚函数,表示启用动态绑定。使用基类的引用或者指针作为函数的参数。实参可使用基类或派生类。实参的类型决定调用基类虚函数还是派生类的重定义虚函数。这就是多态(动态绑定)。多态是通过基类的引用或者指针来实现的。

static成员函数不能定义为虚函数(需要的时候直接定义为子类的静态函数即可)。

static标识符作用:1、隐藏-全局变量、函数其他文件可见,加上static以后本文件可见。2、保持变量内容持久3、static变量(全局区的都会)一定会初始化为0。

对于使用父类的指针或者引用调用非虚函数,不管子类有没自定义的函数版本,编译时已经确定调用父类版本函数。
如传入了子类引用,但不需要使用动态绑定,可用父类作用于classbase::func()来强制使用父类虚函数调用。
 
15.2.5三种继承方式
公有继承:子类保持父类的访问标签,父类为public的子类也为public,父类protect子类也是protect
保护继承:父类的public和protect都变成子类的protect
私有继承:无论父类的标签如何,子类全部变成private
  public protected private
公有继承 public  protected 不可见
私有继承 private private 不可见
保护继承 protected protected 不可见
通过公有函数接口可以访问不可见的成员变量。
 
概念:
派生类代码指的是实现派生类的代码。派生类用户是指使用派生类对象的人,这些人不能改变派生类代码,只能使用派生类。

无论哪一种继承方式,派生类代码对成员的访问权限都一样,都根据父类标签决定。

继承方式决定了派生类用户对成员的访问权限。
如:class son:private father{int k=i;//i是父类的保护成员}//OK,虽然继承下来i是private,但可以访问自己的私有成员。
son s;  int k=s.i;//ERROR,派生类用户不可以使用私有成员。

 

友元不能继承。如果派生类需要设置友元,则需自身重新设置,并不会继承父类的友元设置。
整个继承层次中,static成员只会有一个实例。也就是说父类和派生类共用static实例。

 

派生类的构造哈数可以包含基类在初始化列表中初始化基类成员,但不可以直接初始化基类成员,如
son():a(1),b(2),father(3,3){}//父类father含有两个成员,初始化为3 3

 

通过在函数参数列表后加=0说明次函数是纯虚函数。纯虚函数的作用是作为接口供子类继承,但在本版本中不能使用。virtual void func()=0;
只有重载了纯虚函数的版本才能产生实例,否则会编译错误。含有纯虚函数的类为抽象类
 
为何要使用初始化成员列表
调用类的构造函数分为两个过程:1、初始化过程 2、执行构造函数过程。初始化过程先执行。如有初始化成员列表,则按成员列表初始化,否则为各成员调用默认构造函数进行初始化。完成初始化阶段后,再执行构造函数。
  因此,如在执行构造函数时才对成员进行赋值初始化,则会导致各成员先调用一次默认构造函数,再在执行阶段使用赋值函数,浪费效率。因此,能使用初始化列表的尽量使用。
class test
{
    int a;
public:
    test(){
        cout<<"default constructor"<<endl;
    }
    test& operator=(test &t){
        this->a=t.a;
        cout<<"= operator"<<endl;
        return *this;
    }
    test(test &t){
        this->a=t.a;
        cout<<"copy constructor"<<endl;
    }
};

class test2
{
public:
    test a;
    test2(test &t){
        a=t;
    }
};

int main()
{
    test a;
    test b=a;//初始化,就算使用=,也是调用copy constructor
    test c(a);
    a=b;
    cout<<endl;
    test2 e(a);//先输出defaut constructor,再输出= operator
    return 0;
}

 

posted @ 2012-11-04 22:40  iyjhabc  阅读(188)  评论(0编辑  收藏  举报