c++ 基本语法学习

来源:互联网 发布:约瑟夫环java链表实现 编辑:程序博客网 时间:2024/06/07 08:36

        • 命名空间
          • 命名空间定义方法
          • 命名空间属性调用
          • 案例
          • 上述案例说明
          • 命名空间引用冲突
          • 命名空间嵌套
        • 输出函数
          • 案例
        • 结构体
          • 如果修饰符含有privat 不能创建
        • 变量引用
          • 二级指针和引用
        • 三目运算符
        • 指针常量和常量指针
        • 实参形参
        • bool类型
        • 字符串string
        • 函数重载
        • 类 class
          • 简单创建一个类 实例化
          • 析构函数
          • 拷贝构造方法
          • 拷贝函数问题
          • 类静态属性方法初始化
          • 在头文件中声明类和实现
          • 直接在构造函数初始化一些数值
          • 常函数
          • malloc 和new 的区别
          • 友元函数
        • 运算符重载
    • 未完待续

命名空间

前言(转载自百度百科):命名空间是用来组织和重用代码的 。如同名字一样的意思,NameSpace(名字空间),之所以出来这样一个东西,是因为人类可用的单词数太少,并且不同的人写的程序不可能所有的变量都没有重名现象,对于库来说,这个问题尤其严重,如果两个人写的库文件中出现同名的变量或函数(不可避免),使用起来就有问题了。为了解决这个问题,引入了名字空间这个概念,通过使用 namespace xxx;你所使用的库函数或变量就是在该名字空间中定义的,这样一来就不会引起不必要的冲突了

命名空间定义方法:
//定义命名空间namespace XiaoWang{    char * age="小王";}namespace ZhangSan{    char * age="张三";}
命名空间属性调用:
int main(){    //引用命名空间的age变量输出 cout和endl输出方法 类似printf    cout<<ZhangSan::age<<endl;    std::cout<<XiaoWang::age<<std::endl;    return 0;}
案例:
#include<stdio.h>#include<iostream>using namespace std;//定义命名空间namespace XiaoWang{    char * age="小王";}namespace ZhangSan{    char * age="张三";}int main(){    //引用命名空间的age变量输出    cout<<ZhangSan::age<<endl;    std::cout<<XiaoWang::age<<std::endl;    return 0;}

结果 :
张三
小王

上述案例说明
  1. using namespace std; 再此声明以后的函数使用命名空间std
    此声明是用于 cout函数
    我们删除上面这句话的看看
    这里写图片描述

    • 解决办法1:
      在开头声明using namespace std;

    • 解决办法2:
      在函数前添加命名空间

    int main(){    //引用命名空间的age变量输出    std::cout<<ZhangSan::age<<std::endl;    std::cout<<XiaoWang::age<<std::endl;    return 0;}
命名空间引用冲突

当你引用了两个命名空间,而两个空间都有age这个属性时,需要手动在函数前指明

这里写图片描述

命名空间嵌套:
/* * test.cpp * *  Created on: 2017��4��25�� *      Author: FMY */#include<stdio.h>#include<iostream>using namespace std ;//定义命名空间namespace A{namespace B{ char * test ="测试";}}int main(){    cout<<A::B::test<<endl;    return 0;}

输出函数

c语言输出函数printf 对应c++的cout函数
1. cout 函数 位于iostream下
2. 命名空间std
3. 输出方式:
1. std::cout<< 输出内容 ;
- 这样输出不换行
2. std::cout<< 输出内容<< endl;
- 换行输出 ,输出此语句后自动换行
3. std::cout << 输出内容1<<输出内容2 << endl << 输出内容3
- 可以继续拼接输出内容期间可以嵌套endl

案例
#include<stdio.h>#include<iostream>using namespace std ;//定义命名空间namespace XiaoWang{    char * age="小王";}namespace ZhangSan{    char * age="张三";}int main(){    using namespace ZhangSan;    //以后的代码出现age都是ZhangSan的    cout<<age<<endl;    //除非这样下    cout<<XiaoWang::age;    cout<<XiaoWang::age<<endl<<age;    return 0;}

结果:
张三
小王小王
张三


结构体

#include<stdio.h>#include<iostream>using namespace std ;struct person{//如果不写访问修饰符默认为 publicpublic:    char name [20];    int age;public:    int weight;    void (*eat)(char * food);};void eat2(char *food){    cout<<"我在吃"<<food<<endl;}int main(){    //不需要写 struct 并且增加访问符号    person p{"asd",1,1,eat2};    p.eat("asd");    return 0;}
如果修饰符含有privat 不能{}创建

这里写图片描述

变量引用

前言:就是某一变量(目标)的一个别名,对引用的操作与对变量直接操作完全一样。(次句话转自某博文)

#include<iostream>using namespace std;struct MyStruct{    char *name;};int main(){    int a = 1;    int b = 27;    //给a变量取别名c     //修改c变量会直接修改a变量    int &c = a;    //此时a也会变成23    c = 23;    MyStruct    p1{ "阿斯顿" };    //给p取别名    MyStruct    &p2 = p1;    //此时 p.name也会变    p2.name = "爱迪生";    cout << a<<endl;    cout << p2.name;    getchar();    return 0;}

输出:
23
爱迪生

#include<iostream>using namespace std;struct MyStruct{    char *name;};//返回同一个引用 由于是static 修饰 所以访问的是同一个int & test(){    //静态修饰的只会第一次调用的时候执行a = 23    static int a = 23;    return ++a;}//每次从栈返回 一个引用 不推荐 int& test2(){    int a = 222;    return ++a;}int main(){    cout << test() << endl;    cout << test() << endl;    int c = test2();    cout << test2() << endl;    cout << test2() << endl;    getchar();    return 0;}

输出
24
25
223
223

二级指针和引用
#include<stdio.h>#include<iostream>#include<string.h>#include<stdlib.h>using namespace std ;struct Man{    char*name;};int main(){    Man *m1 = (Man*) calloc(sizeof(Man),1);    m1->name ="你好兄弟";    Man ** m2   = (Man**) calloc(sizeof(Man*),1);;    m2 = &m1;    cout<<"一级指针"<<m1->name<<endl;    cout<<"二级指针"<<(*m2)->name<<endl;    //-----------------引用和二级指针-----------------------    Man *aaa = (Man*) calloc(sizeof(Man),1);    //以下这种方法是错误,因为我们说过引用是取别名 ,你没有原本的名字变量 怎么取别名?    //Man &aaa = (Man*) calloc(sizeof(Man),1);    Man* &mm1 =  aaa;    mm1->name = "嘿嘿";    cout<<"二级引用"<<mm1->name<<endl;    return 0;}

三目运算符

前言:
在c++中三目的的结果可以作为 表达式左值

#include<stdio.h>#include<iostream>#include<string.h>using namespace std ;int main(){    int a = 1;    int b = 2;    *((a>b)?&a:&b) = 232;    cout<<b<<endl;    return 0;}

结果:232

指针常量和常量指针

这里写图片描述

实参形参

在 java方法中传入一个对象 ,在方法中修改对象会直接影响实参 .
c++ 中除非运用指针,或者引用 .不然不会引起实参变化

/* * test.cpp * *  Created on: 2017��4��25�� *      Author: FMY */#include<stdio.h>#include<iostream>#include<string.h>using namespace std ;struct Man{ char *name;};//传入的时候把实参拷贝一份在方法栈区void test( Man p){    //此时修改并不影响调用方法的实参    p.name ="修改";}int main(){    Man man {"旧的"};    //传入的时候把实参拷贝一份在方法栈区    test(man);    cout<<man.name<<endl;    return 0;}

结果:旧的

bool类型

/* * test.cpp * *  Created on: 2017��4��25�� *      Author: FMY */#include<stdio.h>#include<iostream>#include<string.h>using namespace std ;int main(){    bool flag = true;//  bool flag = 1;//这里也是可以赋值数值类型的    if(flag){        cout<<"真的"<<endl;    }else{        cout<<"假的"<<endl;    }    cout<<"bool所占用字节数"<<sizeof(bool)<<endl;    return 0;}
结果:真的bool所占用字节数1

字符串string

因为string的使用和java差不多所以这里不打算说太多

#include<stdio.h>#include<iostream>#include<string.h>#include<stdlib.h>using namespace std ;int main(){    string testString = "hello world";    cout<<"输出字符串"<<testString<<endl;    cout<<"输出字符串 长度"<<testString.length()<<endl;    //转化为char*    const char * convertChar = testString.c_str();    cout<<"转换为char*  "<< convertChar<<endl;    return 0;}

输出
输出字符串hello world
输出字符串 长度11
转换为char* hello world

函数重载

我们在java的时候调用方法是支持重载的,可以根据实参传入的类型和个数位置不同确定调用哪一个方法

#include<stdio.h>#include<iostream>#include<string.h>#include<stdlib.h>using namespace std ;void my(char * name){    cout<<"my(char * name)   ----"<<name<<endl;}void my(int  name){    cout<<"my(int * name)   ----"<<name<<endl;}int main(){    //根据传入的参数类型和个数确定调用哪个类型    my("sd");    my(1);    return 0;}

类 class

简单创建一个类 实例化

new的对象需要用delete删除堆内存

#include<stdio.h>#include<iostream>#include<string.h>#include<stdlib.h>#include <stdio.h>#include <stdarg.h>using namespace std ;class man{public :    char * name ;    //构造方法    man(char *name){        cout<<"构造方法"<<endl;        this->name =name;    }};int main(){    //这种创建方式会 在栈中创建 ,对象可控性不强    man a("Asd");    //和上面的一样    man b = man ("Asd");    //如果使用new的方式 需要 delete删除,因为new是从堆创建的所以和malloc    man * c = new man ("new 创建");    //从堆中删除c    delete c;    return 0;}

输出:
构造方法
构造方法
构造方法

析构函数

在对象被回收的时候调用的时候回调的方法
在c++中析构函数为 ~对象名字()
tip:在java中析构函数名字finalize()

    #include<stdio.h>    #include<iostream>    #include<string.h>    #include<stdlib.h>    #include <stdio.h>    #include <stdarg.h>    using namespace std ; class man{    public :        char * name ;        ~man(){            cout<<"析构函数" <<this<<endl;        }    };    int main(){        man *a=new man ();        delete a;        return 0;    }

输出
析构函数0x1f1f60

拷贝构造方法

应用场景 对象 A = 对象B
此时会回调对象拷贝构造方法

#include<stdio.h>#include<iostream>#include<string.h>#include<stdlib.h>#include <stdio.h>#include <stdarg.h>using namespace std ;class man{public :    char * name ;    man(char * name){        this->name = name;    }};int main(){    man * a=new man ("a");    man b = *a;    b.name= "b";    cout<<a->name<<endl;    return 0;}

输出:
a

这里学java的同学转c++可能不理解,这里man b = *a; 是将对象a中数值拷贝一份创建一个备份生成,两者互不联系

上面的拷贝拷贝函数没有写 ,是因为系统默认帮我们写了.实际中默认写法如下

#include<stdio.h>#include<iostream>#include<string.h>#include<stdlib.h>#include <stdio.h>#include <stdarg.h>using namespace std ;class man{public :    char * name ;    man(char * name){        this->name = name;    }    //默认拷贝方法 ----值拷贝 浅拷贝    man(const man& p){            this->name = p.name;    }};int main(){    man * a=new man ("a");    man b = *a;    b.name= "b";    cout<<a->name<<endl;    return 0;}
拷贝函数问题
#define _CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<iostream>#include<string.h>#include<stdlib.h>#include <stdio.h>#include <stdarg.h>using namespace std ;class Man{public:    char *name;public:    Man(char *name){        this->name = (char*)malloc(100);        strcpy(this->name,name);        cout << "构造函数" << endl;    }    ~Man(){        //释放内存        free(this->name);        cout << "析构函数" << endl;    }    void myprint(){        cout << name << endl;    }};void func(){    Man m1((char*)"fmy");    Man m2 = m1;    strcpy(m1.name,"asd");    m2.myprint();}int main(){    func();    return 0;}

上面的代码会在某些编译器运行奔溃:
原因:man类对象中name进行拷贝的时候是直接将指针赋值另一个对象,导致两个对象共用一个,当其中一个销毁的时候,因为name也会被销毁.可是他们共用引起了野指针

解决办法:用深度拷贝

#define _CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<iostream>#include<string.h>#include<stdlib.h>#include <stdio.h>#include <stdarg.h>using namespace std;class Man{public:    char *name;public:    Man(char *name){        this->name = (char*)malloc(100);        strcpy(this->name, name);        cout << "构造函数" << endl;    }    ~Man(){        //释放内存        free(this->name);        cout << "析构函数" << endl;    }    Man(const Man& m){        this->name = (char *)malloc(sizeof(char)* 111);        strcpy(this->name, m.name);    }    void myprint(){        cout << name << endl;    }};void func(){    Man m1((char*)"fmy");    Man m2 = m1;    strcpy(m1.name, "asd");    m2.myprint();}int main(){    func();    getchar();    return 0;}
类静态属性方法初始化
  • 案例1.初始化静态变量
    这里写图片描述
    可以看到上面报错了.那么到底怎么初始化变量呢?
#define _CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<iostream>#include<string.h>#include<stdlib.h>#include <stdio.h>#include <stdarg.h>using namespace std ;class Man{public :    static int a ;};int Man::a =22;int main(){    cout<<Man::a<<endl;    Man::a =2;    cout<<Man::a<<endl;    Man s();    return 0;}

输出
22
2

  • 案例2静态方法
#define _CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<iostream>#include<string.h>#include<stdlib.h>#include <stdio.h>#include <stdarg.h>using namespace std ;class Man{public :    static void aa(){        cout<<"静态方法aa"<<endl;    }    static void bb();};void Man::bb(){    cout<<"bb方法"<<endl;}int main(){    Man::aa();    Man::bb();    return 0;}

输出:
静态方法aa
bb方法

在头文件中声明类和实现

先看test.h

class man{public:    char *name;    void eat();};

再看看实现类

test.cpp

这里写图片描述

发现用 xxx ();初始化的一个变量的时候无法调用内部方法

  • 解决办法1:
    改用new 或者malloc
int main(){     man* m =new man();     m->eat();     m->name = "你好吗?";    getchar();    return 0;}
  • 解决办法2:
    创建一个传入参数不是空的构造方法
class man{public:    char *name;    void eat();    man(int a){    }};
#include<iostream>#include"test.h"using namespace std;void man::eat(){    cout << "asd" << endl;};int main(){    man a(1);    a.name = "asd";    getchar();    return 0;}
直接在构造函数初始化一些数值
常函数

这里写图片描述

malloc 和new 的区别

malloc 创建的对象也会在堆中,但是不会调用class 的构造方法.和构造方法(一般情况下不会,除非你用指针把对象拷贝),其他方式都会调用如 xx(),new xx().

  • 案例1:

    class man{public :    char * name ;    //构造方法    man(char *name){        cout<<"构造方法被调用咯 传入的name===" <<name<<endl;        this->name =name;    }    man(const man& m){        cout<<"拷贝方法"<<endl;        this->name = m.name;    }    ~man(){        cout<<"析构函数"<<endl;    }};int main(){    man  *m = (man* ) malloc(sizeof(man));    free(m);    return 0;}

    输出:无输出

  • 案例2

        #include<stdio.h>    #include<iostream>    #include<string.h>    #include<stdlib.h>    #include <stdio.h>    #include <stdarg.h>    using namespace std ;    class man{    public :        char * name ;        //构造方法        man(char *name){            cout<<"构造方法被调用咯 传入的name===" <<name<<endl;            this->name =name;        }        man(const man& m){            cout<<"拷贝方法" <<this<<endl;            this->name = m.name;        }        ~man(){            cout<<"析构函数" <<this<<endl;        }    };    int main(){        man  *m = (man* ) malloc(sizeof(man));        cout<<"指针m保存的地址"<<m<<endl;        m->name = "嘿嘿";        //将指针保存的内容拷贝到别处man对象上 ,触发拷贝发生 在对象回收后触发析构函数 在栈区创建的对象m2        man m2 = *m;        cout<<"m2的地址"<<&m2<<endl;        //用此方法可以回收 m内存 并且回调析构函数        delete m;        return 0;    }

    输出:
    指针m保存的地址0x6e1f60
    拷贝方法0x61ff18
    m2的地址0x61ff18
    析构函数0x6e1f60
    析构函数0x61ff18

友元函数

当一个类中有私有变量的时候,正常是无法通过xxx.yy去访问的,只能通过函数间接访问.

  • 正常访问私有变量:
    这里写图片描述

  • 友元函数访问私有

#define _CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<iostream>#include<string.h>#include<stdlib.h>#include <stdio.h>#include <stdarg.h>using namespace std ;#include"test.h"class woman {friend void accessmy(woman *p);public:    int age;    char *name;private:    //私有变量    int weight;    void eat(){        cout<<"私有方法eat"<<endl;    }};void accessmy(woman *p){    cout<<"访问"<<p->weight<<endl;}int main(){    woman* m = new woman();    accessmy(m);    return 0;}
  • 案例2
#define _CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<iostream>#include<string.h>#include<stdlib.h>#include <stdio.h>#include <stdarg.h>using namespace std ;#include"test.h"class woman {friend class B;public:    int age;    char *name;private:    //私有变量    int weight;    void eat(){        cout<<"私有方法eat"<<endl;    }};class B{public :    void accessmy(){        //随便访问        w.weight =30;    }private:    woman w;};

运算符重载

我们在使用java的String类型可以用”+”号拼接两个字符串,c++当然也可以.在我们一开始使用cout函数”<<”符号的时候 大家有没有想过他们是怎么做到的?

案例1:

#define _CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<iostream>#include<string.h>#include<stdlib.h>#include <stdio.h>#include <stdarg.h>using namespace std ;#include"test.h"class Point{    public:    int x;    int y;    Point(int x,int y):x(x),y(y){    }};Point operator+(const Point &p1, const Point  &  p2 ){    return Point (p1.x+p2.x,p1.y+p2.y);}int main(){    Point p1(1,3);    Point p2(2,4);    Point p3 = p1+p2;    cout<<"("<<p3.x<<","<<p3.y<<")"<<endl;    return 0;}

案例2

#define _CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<iostream>#include<string.h>#include<stdlib.h>#include <stdio.h>#include <stdarg.h>using namespace std ;#include"test.h"class Point{    public:    int x;    int y;    Point(int x,int y):x(x),y(y){    }    Point operator+( Point  &  p2 ){        return Point (this->x+p2.x,this->y+p2.y);    }};int main(){    Point p1(1,3);    Point p2(2,4);    Point p3 = p1+p2;    cout<<"("<<p3.x<<","<<p3.y<<")"<<endl;    return 0;}

案例3:

//当属性私有时,通过友元函数完成运算符重载class Point{    friend Point operator+(Point &p1, Point &p2);private:    int x;    int y;public:    Point(int x = 0, int y = 0){        this->x = x;        this->y = y;    }       void myprint(){        cout << x << "," << y << endl;    }};Point operator+(Point &p1, Point &p2){    Point t(p1.x + p2.x, p1.y + p2.y);    return t;}void main(){    Point p1(1, 3);    Point p2(2, 4);    //运算符的重载,本质还是函数调用    //p1.operator+(p2)    Point p3 = p1 + p2;    system("pause");}

未完待续

0 0
原创粉丝点击