c++基础知识点三

静态函数的可以对象不用实例化,直接类名.函数名调用


拷贝构造函数:创建一个CExample类包含两个函数,一个构造函数,一个拷贝构造函数,定义一个CExample对象,

CExample B = A; // CExample B(A); 是一样的,那么会自动调用CExample(const CExample& C) 就是我们自定义的拷贝

//构造函数,它必须的一个参数是本类型的一个引用变量。

  1. //全局函数  
  2. CExample g_Fun()  
  3. {  
  4.      CExample temp(0);  
  5.      return temp;  
  6. }  

g_Fun()函数执行到return时,会产生以下几个重要步骤:
(1). 先会产生一个临时变量,就叫XXXX吧。
(2). 然后调用拷贝构造函数把temp的值给XXXX。整个这两个步骤有点像:CExample XXXX(temp);
(3). 在函数执行到最后先析构temp局部变量。
(4). 等g_Fun()执行完后再析构掉XXXX对象。

注:返回对象将调用复制构造函数,而返回引用不会,效率更高


由于const函数可以保证不修改类里面的成员变量,那么变量加上mutable可以抵消


常量(const)和引用在一个类里面定义了必须初始化,如果const一个对象,那么不可以调用非const的成员函数


指针数组的应用:创建一个指针数组,每个指针指向一个MainWindow对象,for遍历每个元素,可以p[i]对每个对象进行操作


struct foo
{
    string name ;
    int id ;
    foo(string s, int i):name(s), id(i){} ; // 初始化列表
};
这里是初始化列表的用法:foo构造函数传进来后,s赋给name,i赋给id


new和delete会自动调用构造析构函数,而malloc和free只会分配内存,不会调用


多继承:

当一个类继承了另外两个类时,那么写它的构造函数也应当这样写

这样调用zajiao的构造函数时候也分别调用了继承的那两个类的构造函数,调用函数方法的时候这样调用区分3个


私有继承是把父类所有变量都变成私有,保护继承是把父类公有变量变成保护变量


假设一个类fushu,代码 fushu fu=10;会自动进行隐式转换也即fushu fu=fushu(10);(该代码和fushu fu=(fushu)10等同)将10作为参数跳转到fushu的构造函数,然而如果我们不想让他进行隐式转换需要在构造函数前面加上explicit,必须前面加上fushu这样的显示转换才可以

这里fushu fu=10可以转化为fushu fu(10);那么我们zhengshu zheng;  fushu fu=zheng这样是不行的两个对象类型不匹配,如何让它成立呢,因为fushu fu=zheng等价为fushu fu(zheng);那我我们在fushu 的构造函数中传参传zhengshu对象就可以了


父类的指针可以用个强转成子类指针访问子类的同名函数

抽象类不可以实例化,把所有接口都实现了才可以实例化,一个或多个虚函数是个指向虚函数表的指针,占4个字节


类模板:


初始化两个类模板,当传入t111时,赋值给t11。传入t222赋值给t22实际调用的时候传入实际类的类型即可



这里final函数必须是虚函数,作用是该函数无法重写

override只存在于子类当中,且函数是父类含有的且是虚函数,用于警示覆写父类的同名函数


一般类里定义一个static变量可以用来记录创建的对象数目

在构造函数中使用new来分配内存时,必须在相应的析构函数汇总使用delete来释放内存,如果使用new[]来分配内存,使用deletel[]来释放


一个对象里面不要这样复制字符串(指针):

sailor.str=sport.str  //这样是字符串的指针复制,这样会析构两次,出错,

string的浅拷贝是让两个不同的指针指向同一块空间,而这在析构的时候会出现将一块空间释放两次,程序会崩溃,因此我们才需要进行深拷贝,即第二个指针开辟和第一个指针一样大小空间,然后将内容复制过去。 

解决办法是深拷贝,同理对象赋值里面包含指针你就要小心了,要用深拷贝

StringBad::StringBad(const StringBad & st)

{

    len=st.len;

    str=new char[len+1];

    std::strcpy(str,st.str);

}

这里this指什么呢,我觉得调用的是String对象里面的方法,所以指String对象

String & String ::operator=(const String & st)

{

    if(this==&st)

    return *this;

}


静态联编:由于重载,编译器必须查看函数参数以及函数名才能确定是哪个参数,这种在编译过程完成的联编叫静态联编

动态联编:编译器必须生成能够在程序运行时选择正确的虚方法的代码


如果定义的类将被用作基类,那么应将这些要在子类中重新定义的类声明为虚的,虚函数为了重载和多态,在基类中有定义,所以子类中可以重写也可以不写,纯虚函数(在虚函数后面加上=0为纯虚)在基类中不定义,必须在子类中加以实现


创建子类对象时,先调用基类的构造方法,然后调用子类的构造方法,删除对象时,先调用子类的析构,在调用父类


抽象模板类:


由于抽象类不能实例化,那么只能用一个指针来进行初始化







使用c++在一个字符串提取子字符串,先创建一个结构体,保存所以可能类型,然后扫描完可以输出所有的子字符串


这里每个字符串中间有个空格所以我们可以提取子字符串,如果每个字符串直接是#我们可以将#换成空格然后。。。


内存映射:对于几TB的海量存储,不能用一些ReadFile,WriteFile这些api来读写文件,将文件从磁盘加载到内存,可以解决多个进程共享数据的问题


Lambda表达式:是一个匿名函数,即没有函数名的函数。,比如在c++中

如果在[]当中加this,说明要引用this

这里->指的返回类型为double


有空看看100条经典的c++笔试题目,




进程间通信的方式

1 管道技术

2 消息队列

3 信号

4 共享内存

5 socket


重载和重写的区别:

重载:允许存在多个同名函数但是参数不同

重写:子类重写父类的虚方法






c++中有一些运算符不允许被重载,比如.  比如#@$



多态:多态分为两类:静态多态性和动态多态性,以前学过的函数重载和运算符重载实现的多态性属于静态多态性,在

程序编译时系统就能决定调用哪个函数,因此静态多态性又称为编译时的多态性。静态多态性是通过函数的重载实现的。

动态多态性是在程序运行过程中才动态地确定操作所针对的对象。它又称运行时的多态性。动态多态性是通过虚函数实现的。

虚函数表:一个类中所有虚函数地址构成的表叫虚函数表,派生类的虚函数地址会覆盖基类的地址,多重继承时,子类没有发生覆盖的函数被放到第一个父类的表中

静态成员函数不能为虚函数,内联函数也不能为虚函数,构造函数不能为虚函数,析构函数可以为虚函数


如果父类的析构函数不是虚函数,那么最后只调用父类的析构,不会调用子类的析构,造成内存泄漏,所以,一定要在父类析构设成虚的,才会父类子类都调用析构函数


使用string类,不能将一个数组赋给另一个数组,但可以将一个string对象赋给另一个对象

char char1[20];

char char2[20]="sdfsd";

char1=char2;  //不允许

string str1;

string str2="sdfsdf";

str1=str2;   //可以这样做

str str3;

str3=str1+str2;  // 将两个str2放到str1后面


共用体union的长度为最大成员的长度。用于节省内存

面向对象与传统的过程编程区别在于OOp强调在运行阶段而不是编译阶段进行决策

long * fellow;

*fellow=233;      //指针指向哪里呢,因此指针必须要初始化为一个确定合适的地址

c语言的初始化指针:

int higgens;

int *pt=&higgens;

c++指针初始化:

int *pn=new int;  //如果int *pt;   pt=0xB800000;这样类型不对pt=(int *)0xB80000才对


编译时给数组分配内存叫做静态联编

int tacos[10];

new在运行时需要数组就创建它并创建长度,不需要就不创建,叫动态联编

int size;

cin>>size;

int *pz=new int[size];

delete[] pz;


问:什么时候用.什么时候用->

答:如果是结构名用.如果是指针指向结构用->    比如(*ps).name这里*ps指向结构实体,ps->name这里ps是某个结构体指针


new char数组是[]里面都是strlen[a]+1这里+1是‘\0’如果new 出来的数组没有赋值那么声明的空间大小中每个元素都是'\0'


对于一个数组ar如果ar+4==&ar[4]表示的是第五个元素的地址

const  float  g_earth=9.8;

const  float  *pe=&g_earth;       // 这个是正确的,既不能修改变量也不能修改指针


const  float  g_earth=9.8;

float *pm=&g_earth;           //这是不对的

这样可以用pm修改g_earth,因此c++禁止将const地址赋给非const指针


double pam(int);   这是一个函数原型,函数名为pam,若求该函数的函数指针,意思是把函数变成指针的形式,double (*pf)(int)这里指针pf就是函数指针


const double *(*pa[3]) (const double *, int)

看这个要一层一层看:pa[3]看成double pa[3]明显是个包含3个元素的数组,*pa[3]看成double *pa[3]明显是个包含3个指针的数组,然后再看最外层,const double*    (const double,int)  这是一个函数返回double的指针

最后这样回答:pa是一个包含三个指针的数组,每个指针指向这样的函数:const double*和int作为参数,返回值为const double*


对于double pa[3]这个数组,pa和&pa还是有区别的,pa指的是第一个数组元素的地址&pa[0]但是&pa是整个数组的地址,也即三个double的地址,比如pa+1为下一个元素地址,&pa+1为pa地址+3*8字节的地址


double *pd[3] 表示有3个元素为double指针的数组

double (*pd)[3] 表示pd是一个指针,指向3个元素为double的数组


函数指针:

int func(int x); /* 声明一个函数 */
int (*f) (int x); /* 声明一个函数指针 */
f=func; /* 将func函数的首地址赋给指针f */
或者使用下面的方法将函数地址赋给函数指针:
f = &func;

赋值时函数func不带括号,也不带参数,由于func代表函数的首地址,因此经过赋值以后,指针f就指向函数func(x)的代码的首地址。


指针函数和函数指针的区别:

指针函数是指返回值是指针的函数,即本质是一个函数。

函数指针是指向函数的指针变量。 


函数模板:

template<typename T>         //关键字template和typename是必须这样写或者把typename改成class也行

void Swap(T &a,T &b){

}

在调用函数的时候Swap<double>(4,5); 在函数名后面加上尖括号跟上泛型类型


在多文件程序中,可以在一个文件中定义一个外部变量,使用该变量的其他文件必须使用关键字extern


double *pd=new double(99)     //   *pd初始化为99


Jill::fetch是取得Jill里面的变量fetch,而using Jill::fetch这里using是将对象Jill里的变量fetch放到局部空间中,因此不能再声明局部变量fetch了,如果取得全局变量fetch用  ::fetch来得到


using namespace作用是让名称空间中所有名称都可用,using namespace Jack;让Jack里面所有名称都可用


当运算符函数是成员函数,第一个操作数将是调用该函数的对象,定义运算符函数如果第一个操作数不是类对象必须使用友元函数:

Time operator*(double n) const;   //这里重载&运算符

friend Time operator*(double m,const Time &t)  {return t *m}    //但是对象*整数可以如果整数*对象就无法执行。如果*前面不是类对象就必须用友元函数


深拷贝与浅拷贝:

StringBad headline("dfsdfsdfdsfd");

StringBad knot;

knot=headline;    //两个对象复制,这里是浅拷贝,这样的结果是数据受损,对knot析构,删除了字符串“dfsdfsdfdsfd”,当对headline调用析构是,试图删除已经删除的字符串,导致结果不确定,程序异常终止

解决办法:

重载=号运算符让对象复制实现深拷贝


c++中拷贝构造函数和赋值运算符不同点:

1.拷贝构造函数只是在对象实例化时才被调用,也即在调用拷贝构造函数期间,对象处于一个未决状态(直到拷贝构造函数被成功调用);而赋值运算符则在一个现存的对象被赋予新值时被调用。

2.拷贝构造函数没有返回值;赋值运算符有返回值。

举例:

class T  
{  
    private:  
        static int count;  
    public:  
        T() {  
            count++;  
            cout<<"create T "<<endl;      
        }  
        T(const T& t)            //拷贝构造函数   
        {  
            count++;  
            cout<<"copy create T "<<endl;  
        }  
        T& operator=(const T& t) //赋值运算符   
        {  
            count++;  
            cout<<"assignment op "<<endl;  
            return *this;  
        }         
};  
int T::count = 0;  
     
int main(int argc, char** argv) {  
    T t;  
    T t1 = t;                  //调用拷贝构造函数   
    T t2(t);                   //调用拷贝构造函数   
    t1 = t2;                   //调用赋值运算符   
    T t3 = t2 = t1;            //先调用赋值运算符,在调用拷贝构造函数   
    return 0;  
}  

摘自http://blog.csdn.net/wjf201003050643/article/details/52745050


pc1=new (buffer) JustTesting;  //意思是new一个JustTesting对象地址和buffer这个数组地址一样


c++中多态的定义:同一个方法在子类和父类的实现是不同的。有两种机制用于实现多态:1子类重新定义父类方法2虚方法

但是博客中定义的多态是这样的:

多态:父类型的引用可以指向子类型的对象。
比如 Parent p = new Child();
当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;
如果有,再去调用子类的该同名方法。
如果想要调用子类中有而父类中没有的方法,需要进行强制类型转换,如上面的例子中,将p转换为子类Child类型的引用

class Student{

    private:

        std::string name;

        ArrayDb scores;

    public:

        Student() : name("Null Student") ,scores(){} //意思是声明Student的构造函数,初始化name和scores为Null Student和空


使用私有继承,基类的公有成员和保护成员都成为子类的私有成员

class Student : private std::string, private std::valarray<double>{      //私有继承,多继承     }


32位系统指针长度为4字节, 64位系统 指针长度为8字节

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值