c++ 基本语法学习

命名空间

前言(转载自百度百科):命名空间是用来组织和重用代码的 。如同名字一样的意思,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{

//如果不写访问修饰符默认为 public
public:
    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");
}

未完待续

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值