c++语法1

android底层是用c++实现的,java实现的是应用程层,为了后续学习android系统底层的源码,首先要了解c++的语法。
这里只是简单的快速了解C++,作为学习笔记

  • 访问控制:
    C++中是通过关键字: public 、private、 protected ,以及命名空间实现。java中也是通过这三个关键字加package实现。我们封装Person信息:

person.cpp:

#include 
// my first program in C++
class Person {
private:
    char *name;
    int age;
    char *work;
public:
    void setName(char *name){
        this->name = name;
    }
    int setAge(int age){
        if (age < 0 || age > 150){
            this->age = 0;
            return -1;
        }
        this->age = age;
        return 0;
    }
    void printInfo(void){
        printf("name = %s, age = %d, work = %s\n", name, age, work); 
    }
};
int main(int argc, char **argv){
    Person per;
    per.setName("zhangsan");
    per.setAge(200);
    per.printInfo();    
    return 0;
}

我们将成员使用private隐藏起来,只提供公用方法。

  • 程序结构:
    在person.cpp中我们可以将定义与实现分离出来,这样让使用Person类的人不用关心具体是怎么实现的。定义我们使用.h文件。
    person.h
#include 
class Person {
private:
    char *name;
    int age;
    char *work;
public:
    void setName(char *name);
    int setAge(int age);
    void printInfo(void);
};

person.cpp实现:

#include 
#include "person.h"
void Person::setName(char *name){
    this->name = name;
}
int Person::setAge(int age){
    if (age < 0 || age > 150)
    {
        this->age = 0;
        return -1;
    }
    this->age = age;
    return 0;
}
void Person::printInfo(void){
    printf("name = %s, age = %d, work = %s\n", name, age, work); 
}

对于使用者,只需要引入person.h

#include 
#include "person.h"
int main(int argc, char **argv){
    Person per;
    per.setName("zhangsan");
    per.setAge(200);
    per.printInfo();
    return 0;
}

除此之外,如果我们要提供两个同名Person类,一个是中国人,一个美国人。如果在java中我们可以通过引用不同包名解决类同名的问题,在c++中则使用命名空间来解决。实现Person时用
namespace C包裹,代表中国人:

namespace C {
  Person ....
}

使用namespace U包裹,代表美国人:

namespace U {
  Person ....
}

在需要时使用using C::Pserson或using U::Pserson引入。引入位置可以是全局的,也可以是局部的。引入可以是类或者类中的方法。

  • 重载、指针、引用:
    • 重载:函数或者方法有相同的名称,但是参数列表不相同的情形,这样的同名不同参数的函数或者方法之间,互相称之为重载函数或者方法。参数列表不同包括参数的个数不同、类型不同或顺序不同,仅仅参数名称不同是不可以的。函数返回值也不能作为重载的依据
#include 
using namespace std;
int add(int a, int b){
    cout<<"add int+int"<
  • 操作符重载:
    例如+操作符不支持Point类,我们可以重载+操作符实现Point相+
#include 
#include 
#include 
using namespace std;
class Point {
private:
    int x;
    int y;
public:
    Point() {}
    Point(int x, int y) : x(x), y(y) {}
    int getX(){ return x; }
    int getY(){ return y; }
    void setX(int x){ this->x = x; }
    void setY(int y){ this->y = y; }
    void printInfo(){
        cout<<"("<

输出:

Point operator+(Point &p1, Point &p2)
(3, 5)

对于+-*/都使用类似方式实现重载。

  • 指针、引用:
#include 
using namespace std;
int add_one(int a){
    a = a+1;
    return a;
}
int main(int argc, char **argv){
    int a = 99;
    cout<name = name;
    }
    Person(char *name, int age, char *work = "none") {
        cout <<"Pserson(char*, int)"<name = name;
        this->age = age;
        this->work = work;
    }
    void setName(char *n){
        name = n;
    }
    int setAge(int a){
        if (a < 0 || a > 150){
            age = 0;
            return -1;
        }
        age = a;
        return 0;
    }
    void printInfo(void){
        //printf("name = %s, age = %d, work = %s\n", name, age, work); 
        cout<<"name = "<

输出:
Pserson(char*, int)
Pserson()
name = zhangsan, age = 16, work = none
这里我们在调用无参构造函数时不需要带() Person per2,如果是Person per2()则是函数的声明,类似int fun();,而不是调用构造方法了。
Person(char *name, int age, char *work = "none")这个构造函数定义了work的默认值。

除此之外我们还可以用指针来初始化对象,并且为成员分配空间。

#include 
#include 
using namespace std;
class Person {
private:
    char *name;
    int age;
    char *work;
public:
    Person() {cout <<"Pserson()"<name = new char[strlen(name) + 1];
        strcpy(this->name, name);
    }
    Person(char *name, int age, char *work = "none") {
        cout <<"Pserson(char*, int)"<age = age;
        this->name = new char[strlen(name) + 1];
        strcpy(this->name, name);
        this->work = new char[strlen(work) + 1];
        strcpy(this->work, work);
    }
    void setName(char *n){
        name = n;
    }
    int setAge(int a){
        if (a < 0 || a > 150){
            age = 0;
            return -1;
        }
        age = a;
        return 0;
    }
    void printInfo(void){
        //printf("name = %s, age = %d, work = %s\n", name, age, work); 
        cout<<"name = "<printInfo();
    per8->printInfo();
    delete per4;
    delete per5;
    delete []per6;
    delete per7;
    delete per8;
    return 0;
}

输出:

Pserson(char*, int)
Pserson()
Pserson()
Pserson()
Pserson()
Pserson()
Pserson(char*, int)
Pserson(char*, int)
name = zhangsan, age = 16, work = none
name = lisi, age = 18, work = student
name = wangwu, age = 18, work = none

可以看到我们使用new 的方式创造的都会调用对应的构造函数,分配的堆内存可以手动释放。但是我们给成员分配的堆空间没有释放。我们可以使用析构函数释放堆空间

    ~Person(){
        if (this->name)
            delete this->name;
        if (this->work)
            delete this->work;
    }

析构函数:
与构造函数相反,当对象结束其生命周期时(例如对象所在的函数已调用完毕),系统自动执行析构函数。析构函数往往用来做“清理善后” 的工作(例如在建立对象时用new开辟了一片内存空间,delete会自动调用析构函数后释放内存)。

拷贝构造函数:
又称复制构造函数,是一种特殊的构造函数,它由编译器调用来完成一些基于同一类的其他对象的构建及初始化。其唯一的形参必须是引用,但并不限制为const,一般普遍的会加上const限制。此函数经常用在函数调用时用户定义类型的值传递及返回。拷贝构造函数要调用基类的拷贝构造函数和成员函数。

构造函数与析构函数调用时机:这里我们将添加全局构造对象,main构造对象,局部构造对象,以及静态的。

#include 
#include 
#include 
using namespace std;
class Person {
private:
    char *name;
    int age;
    char *work;
public:
    Person() {//cout <<"Pserson()"<name = new char[strlen(name) + 1];
        strcpy(this->name, name);
        this->work = NULL;
    }
    Person(char *name, int age, char *work = "none") {
        cout <<"Pserson(char*, int), name = "<age = per.age;
        this->name = new char[strlen(per.name) + 1];
        strcpy(this->name, per.name);
        this->work = new char[strlen(per.work) + 1];
        strcpy(this->work, per.work);
    }
    ~Person(){
        cout << "~Person()"<name) {
            cout << "name = "<name;
        }
        if (this->work) {
            cout << "work = "<work;
        }
    }
    void setName(char *n){
        name = n;
    }
    int setAge(int a){
        if (a < 0 || a > 150){
            age = 0;
            return -1;
        }
        age = a;
        return 0;
    }
    void printInfo(void){
        //printf("name = %s, age = %d, work = %s\n", name, age, work); 
        cout<<"name = "<

输出:

//先调用全局构造
Pserson(char*, int), name = per_g, age= 10
//main构造
Pserson(char*, int), name = per_main, age= 11
//main静态
Pserson(char*, int), name = per_main_s, age= 11
//进入for循环,func函数中局部
Pserson(char*, int), name = per_func, age= 11
//局部静态
Pserson(char*, int), name = per_func_s, age= 11
//func函数结束后会调用func中per_func对象的析构函数,但是没有调用静态对象的析构函数!
~Person()
name = per_func
work = none
//for循环中创建对象
Pserson(char*, int), name = per_for, age= 0
//第一次for循环结束后执行for循环中per_for对象的析构函数
~Person()
name = per_for
work = none
//第二次for循环,进入func方法,但是没有创建func中静态对象
Pserson(char*, int), name = per_func, age= 11
//func函数结束后,执行析构
~Person()
name = per_func
work = none
//创建for循环中的对象
Pserson(char*, int), name = per_for, age= 1
//for循环结束后
~Person()
name = per_for
work = none
//main函数结束,但是没有执行main中的静态对象
~Person()
name = per_main
work = none
//调用func中的静态析构
~Person()
name = per_func_s
work = none
//调用main中的静态析构
~Person()
name = per_main_s
work = none
//调用全局的析构
~Person()
name = per_g
work = none

从上面的输出我们看到:
1 对于静态的实例化对象,如果已经创建过了,则不会再创建了。例如第二次for循环的时候就没有再次创建per_func_s静态对象。
2 静态对象只会在main结束前调用析构。

总结下构造顺序:按运行中定义对象的顺序调用构造函数,静态对象只调用一次构造函数,全局对象在main函数执行前被构造。

下一篇继续学习静态成员、友元函数、继承、多重继承,继承访问权限

你可能感兴趣的:(c++语法1)