C++入门(适合熟悉Java语言的开发者入门)

    在鹅场,c/c++才是王道,工作需要,又得拾起c/c++。

一、指针与引用

    1. Java简单的地方就是摒弃了指针,一个指针变量存放的内容就是所指对象的地址。(对一个变量求地址,可以使用&)

int main(){
     int a = 3; 
     int *p = &a; //p指向a的地址
     int **q = &p; //q指向p地址
     cout <<a<<" "<<*p<<" "<<&a<<" "<<p<<" "<<&p<<" "<<q<<endl;
     return 0;
}

输出如下:
   
 3 3 0x28ff18 0x28ff18 0x28ff14 0x28ff14

指针存放的是地址,所以p存放的就是a地址,*p就是指向地址的内容,也就是0x28ff28,直接输出p,则输出a的地址,也就是0x28ff28,&p就是输出p的地址,所以q的存放内容也就是p的地址0x28ff24
    
    2. 引用,在很多Java的经典书籍中,我们常常看到reference,大多翻译成引用,C++的引用与Java还是有所不同的,C++的引用可以理解成就是变量别名,Java的引用可以改变指向的实例,特别是在函数传参的时候,对于基本类型,Java是直接拷贝变量值传参,对于对象都是通过引用拷贝(跟C++中引用不同)传参,通过应该引用能够更改其指向的对象内部值,但是更改该引用值,仅对函数内部可见,函数外部的实参依然没有改变。 C++的引用需要在初始化就指定引用的对象,并且不可变换。
    如果我们想要swap两个变量,对于Java来说,如果变量是基本类型,不好意思,做不到。对于是对象类型,则可做到。
    但C++不同,有了引用这一强大的功能,可以轻易做到,先说说C版本通过指针交换的版本:
   
 void swap(int *a, int *b){
     int temp = *a;
     *a = *b;
     *b = temp;
 };

    有了引用机制,以上程序的C++版本可以为:
    
void swapInt(int &a, int &b){
      int temp = a;
      a = b;
      b = temp;
}


    调用如下:
    
int main() {
     int a = 10;
     int b = 20;
     swapInt(a,b);
     cout<<a<<" "<<b<<endl; //输出20 10
     return 0;
}


二、const

    const 这个是Java的关键字,但只做保留,目前没有定义使用,Java如果要定义属性不可修改可以使用final 关键字,但C++这里使用的是const,在上面的swap函数中,我们知道定义C++函数参数,如果不是引用的话,都是深复制参数,不像Java,比如下面代码段( 这里函数参数并不会深复制,都是形参指向):
    
public static void swapInteger(Integer a, Integer b){
      Integer temp = a;
      a = b;
      b = temp;
}
public static void main(String[] args) {
      Integer a = new Integer(5);
      Integer b = new Integer(10);
      swapInteger(a,b);
      System.out.println(a + " " + b);//输出 5 10
}
   
    但是C++,如果你定义的函数参数不是引用类型的话,是会自动调用拷贝构造函数来浅复制一个新对象来作为函数参数的,比如下面代码:
  
class ClassA
{
public:
    ClassA(){
       cout<<"构造函数"<<endl;
    }

    ClassA(const ClassA &a){
      cout<<"拷贝构造函数"<<endl;
    }

    ~ClassA()
    {
     cout<<"析构函数"<<endl;
    }

    void setI(int i){
     this->i = i;
    }

    int getI(){
     return this->i;
    }

private:
    int i = 0;
};

//参数a是采用ClassA的拷贝构造函数来实例一个对象,然后作为参数的。
void test(ClassA a){
    cout<<a.getI()<<endl;
}

int main() {
   ClassA a1;
   a1.setI(5);
   test(a1);
   return 0;
}



    最终输出:
   
    构造函数
    拷贝构造函数
    0
    析构函数
    析构函数



     以下几种情况都会调用拷贝构造函数:
    1.一个对象以值传递的方式传入函数体
    2.一个对象以值传递的方式从函数返回
    3.一个对象需要通过另外一个对象进行初始化


    
三、深复制与浅复制
    Java的深复制,一般都是通过implements Cloneable 覆盖clone方法来实现深复制。
    一般的变量赋值,比如下面代码都是浅复制,也就是直接引用:
 
   A a = new A();
   A a1 = a; // a1和a都是指向同个实例,对a的修改,也就是对a1的修改

    C++的复制,归于拷贝构造函数,在上面的说明中,我们知道有三种情况会使用到拷贝构造函数。
    C++与Java一样,如果我们没定义构造函数,编译器会自动帮我们构造一个无参数的构造函数,但是如果我们定义了构造函数,那么编译器将不会构造无参构造函数。
    重新定义拷贝构造函数,可以为我们做到更多,比如深复制,而不是使用编译器自己的拷贝规则:基本类型深复制,类类型使用其拷贝构造函数来拷贝。下面用代码举个例子:
 
class ClassA
{
public:
 ClassA();
    ~ClassA();
    void setI(int i); 
    void setName(std::string& n);
    std::string getName() const;
    int getI();
private:
    int i;
    std::string *name;
};

    上述类ClassA并没有定义拷贝构造函数,所以拷贝规则为:int类型深复制,string *类型也是直接复制存放的地址。

int main() {
   ClassA a1;
   string hello("hello");
   a1.setName(hello);
   a1.setI(5);
   ClassA a2 = a1;//拷贝构造
   hello.append(" world");
   a1.setI(10);
   cout<<a2.getI()<<" "<<a2.getName()<<endl;
   cout<<a1.getI()<<" "<<a1.getName()<<endl;
   return 0;
}

     输出:

构造函数ClassA  
5 hello world
10 hello world
析构函数ClassA
析构函数ClassA

    上述例子代码中,a2和a1的name属性都是执行同一个string实例,所以对实例的修改,都会生效。但是i属性则是不同的内存空间,所以a1对i属性的修改并不会生效到a2实例。




   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值