美文网首页
C++基础:类与对象一

C++基础:类与对象一

作者: 慧科集团华东校区 | 来源:发表于2017-08-15 09:38 被阅读0次

作者:慧科集团华东校区-朱家聪老师,转载请注明出处及本链接。

C++的基本语法

include

与C语言中相同,使用#include能够包含系统库和头文件。不能使用#import来进行包含。在C++中所要包含的基础库是iostream。当然也能使用C语言中的标准输入输出库stdio.h,但是在使用时建议使用在C++中的写法。

#include <iostream>
#include <cstdio>   //在C++中的写法,用于包含 stdio.h

cout输出

cout是在iostream中所定义的输出对象,用于向控制台输出数据。

std::cout << "Hello World!" << endl;

在这里用到了一个命名空间标识符“std”,引用他人对std的解释为:

std:: 是个名称空间标示符,C++标准库中的函数或者对象都是在命名空间std中定义的,所以我们要使用标准函数库中的函数或对象都要使用std来限定。
在使用到iostream库中的函数时,需要使用std来进行调用,这么写会导致代码变复杂。所以可以在使用前声明std这个命名空间。

using namespace std;

C++中的类与对象

在C++中,面向对象的概念和Objective-C中基本一致,所以在此只研究代码书写的格式以及两者之间不同的地方。

类的定义

使用class来定一个类,这里以User类为例,这个类有三个私有属性:userID,username,password。

class User{
private:
    int userid;
    string username;
    string password;
        
public:
    bool login(string username, string password){
        this->username = username;
        this->password = password;
        if (this->password == "12345") {
            return true;
        }
        return false;
    };
};

对于类中定义的属性有以下三种修饰符,可以用来定义属性的访问权限。由于面向对象的封装特效,一般我们在定义一个类时,都会将属性定义为私有类型,将方法定义为公共类型。

private: 私有的,只能在当前类中的成员函数中调用
public: 公共的,可以在任意函数中调用
pretected: 受保护的,可以在当前类的成员函数中调用,也可以在派生类的成员函数中调用

对象的创建

在C++中,实例化一个对象有两种操作方法。分别为直接创建对象和使用new关键词来创建对象。

User user1;                     //方法一
User *user2 = new User();       //方法二

方法一:直接实例化对象

直接使用User类来创建一个对象user1。此时所创建的对象user1保存在内存的栈区,由系统自动管理内存。当要调用对象的方法时,使用点语法进行调用。

User user1;
user1.login("zhujiacong", "123456");

方法二:使用new来实例化对象

使用new来实例化的对象,返回值为对象所在的内存地址(指针)。类似于C语言中的malloc()函数,系统会在内存的堆区为对象开辟一块空间,并且需要用户手动管理内存。在使用结束需要使用delete来释放对象所占内存。由于所接收到的是对象所在的内存地址,所以不能使用点语法来访问对象的方法,而是改用箭头符号。

User *user2 = new User();
user2->login("zhujiacong", "123456");
delete user2;

对象的一些用法和特性

this指针的使用

在Objective-C中,可以使用self来替代当前对象。同样的在C++中可以使用this指针来替代当前对象。在User类的getUsername方法中可以使用this来指代当前对象,进而访问到对象中的属性。

class User{
private:
    int userID;
    string username;
    string password;
    
public:
    string getUsername(){
        return this->username;
    };
}

而在类的成员函数中使用到当前对象的属性时,可以省略掉this指针。但是如果这个对象要做为一个整体引用时不能省略。

    string getUsername(){
        return username;
    };

引用 &

引用就是某一变量(目标)的一个别名,对引用的操作与对变量直接操作完全一样。引用的声明方法:类型标识符 &引用名=目标变量名;

int a; int &ra=a; //定义引用ra,它是变量a的引用,即别名
  1. &在此不是求地址运算,而是起标识作用。

  2. 类型标识符是指目标变量的类型。

  3. 声明引用时,必须同时对其进行初始化。

  4. 引用声明完毕后,相当于目标变量名有两个名称,即该目标原名称和引用名,且不能再把该引用名作为其他变量名的别名。

        ra=1; 等价于 a=1;
    
  5. 声明一个引用,不是新定义了一个变量,它只表示该引用名是目标变量名的一个别名,它本身不是一种数据类型,因此引用本身不占存储单元,系统也不给引用分配存储单元。故:对引用求地址,就是对目标变量求地址。&ra与&a相等。

使用场景

在C++的函数使用时,当函数的参数的体积比较大时,直接进行参数的传递,会将实参的值复制给形参。在复制的过程中会占用很大的内存空间和CPU资源。在C语言中通常使用指针的形式来进行参数的传递,而在C++中还可以使用引用类型来解决这个问题。相对来说,使用引用来做完函数的参数。代码更加简洁,也不会给实参重复分配内存空间。

void swap(int &p1, int &p2){
    int temp = p1;
    p1 = p2;
    p2 = temp;
}

int i = 5;
int j = 10;
swap(i, j);
cout << i << "," << j << endl;

常引用

常引用声明方式:const 类型标识符 &引用名=目标变量名;用这种方式声明的引用,不能通过引用对目标变量的值进行修改,从而使引用的目标成为const,达到了引用的安全性。

int a ;
const int &ra=a;
ra=1; //错误
a=1; //正确

假设有如下函数声明:

string foo( );
void bar(string & s);
//那么下面的表达式将是非法的:
bar(foo( ));
bar("hello world");

原因在于foo( )和"hello world"串都会产生一个临时对象,而在C++中,这些临时对象都是const类型的。因此上面的表达式就是试图将一个const类型的对象转换为非const类型,这是非法的。引用型参数应该在能被定义为const的情况下,尽量定义为const 。

引用作为函数的返回值

引用类型也能够作为函数的返回值使用,但是在使用时必须要注意,不能返回一个局部变量的引用。因为局部变量在函数执行完毕之后会自动释放内存。而引用并不会创建新的变量,而是引用向这个已经被释放了的局部变量。这样是一种不安全的操作。一般引用作为返回值多用在类的成员函数中用于返回当前对象。这样可以节省一次值的复制操作。

int &sum(int a, int b){
    int s = a + b;
    return s;
}

对象的生命周期

new 和 delete

new操作符

使用new操作符+数据类型名,能够用于在内存中创建一个用于储存数据的内存空间。可以用于创建任意的数据类型。但是new操作的返回值是一个指向这块内存的指针,所以需要用指针来接受。指针的类型会自动匹配所创建的数据类型。如果使用的是string类型的话,也可以直接对字符串进行初始化。使用类似p4这样的格式能够创建一个数组,并且返回的是数组第一个字符串所在的内存地址。

int *p1 = new int;
string *p2 = new string;
string *p3 = new string("Hello Cpp");
string *p4 = new string[3];

delete操作符

用于释放对象所占内存空间,类似于C语言中的free();函数。使用方法是 delete 对象指针; 这样只能够释放掉单个对象,对于数组需要添加一对中括号。在delete调用之后,需要将所对应的指针置为NULL,防止出现野指针的错误(缅怀一下OC中的weak类型)。在C++中允许使用delete来释放一个空指针,并不会出现错误。但是一般不会这么来做。

delete p1;
delete []p4;

int *p = NULL;
delete p;

new/delete 和 malloc/free的区别

  1. malloc/free 是定义在stdlib.h标准库中的函数;而new/delete是C++的操作符。
  2. malloc需要制定所分配的内存的字节数,不能用于初始化对象;而new会根据所创对象的大小自动来分配。
  3. 使用new会自动调用类对象的构造函数对类对象进行初始化。
  4. malloc函数的返回值是void*;而new的返回类型会根据所创建的数据类型自动匹配指针类型。
  5. malloc运行失败会返回一个NULL;而new失败会抛出异常并自动终止程序。
  6. delete会自动的调用对象的析构函数;而free并不会。

构造函数和复制(拷贝)构造函数

构造函数

用于构造当前对象的函数,这个函数的函数名和当前类的类名一样,参数为需要构造的对象的各个值。具体写法有两种,如下所示。

//第一种写法
User(string s1, string s2){
    username = s1;
    password = s2;
}

//第二种写法
User(string s1, string s2):username(s1),password(s2){}

User user1("zhujiacong", "12345");  //创建一个user1对象,并且自动初始化用户名和密码

默认构造函数

在构造函数的参数后面,可以添加一个默认值。这样在创建对象时如果没有传入合适的参数,就会使用默认参数进行创建。

User(string s1="zhujiacong", string s2="123456"):username(s1),password(s2){}

复制构造函数的调用时机

当我们在初始化一个对象时,需要从另一个已有对象进行属性值的复制,此时就会调用复制构造函数。如下代码创建的user2和user3中的属性的值和user1完全一致。但是通过打印变量所在的内存地址可知他们和user1并不是同一个对象。这个机制类似于OC中的copy方法,是一种深拷贝。

    User user1;
    user1.setUsername("zhujiacong");
    user1.setPassword("123456");
    user1.printUserInfo();
    
    User user2(user1);
    user2.printUserInfo();
    User user3 = user1;
    user3.printUserInfo();

还有两种情况下系统也会调用复制构造函数分别是:

  1. 对象作为函数的实参,并且形参是非引用类型。
  2. 对象作为函数的返回值,并且为非引用类型。

自定义的复制构造函数

在当前类没有自定义的复制构造函数时,系统会自动的给这个类添加默认的复制构造函数。默认复制构造函数的原理是简单的对当前对象中的每一个属性的值进行简单的复制。

//第一种写法
User(const User &u){
    username = u.username;
    password = u.password;
}
//第二种写法
User(const User &u):username(u.username),password(u.password){}

User user2(user1);              //将user1的值进行复制,并且初始化给user2

当这个类中存在指针变量,或者类中有动态分配的内存时。自动的复制构造函数不能够很好的进行数值的复制(例如无法合理的分配堆区内存)。此时就需要手动定义复制构造函数。

User user1("zhujiacong", "12345");
user1.p = malloc(100);
cout << user1.p <<endl;
User user2(user1);
cout << user2.p <<endl;
    
//输出如下
0x100300160
0x0
Program ended with exit code: 0

析构函数

在对象被销毁是调用的函数,类似于OC中的dealloc方法。析构函数没有任何类型,既不属于返回值函数,也不属于void函数。析构函数的格式和构造函数类似,函数名是在类名之前添加一个波浪号~。在析构函数中,通常会对当前类中手动管理内存空间的数据类型,比如指针,进行释放和销毁。

    ~User(){}

C++对象的内嵌

在C++语言的使用过程中,类和对象是最主要使用到的概念。在实际开发中常常要使用到内嵌对象,内嵌对象指的是将一个对象作为一条属性内嵌到另一个类对象中去。在处理这样的类时,需要注意的是类的构造函数中必须要实现对成员对象的初始化。

class A{
private:
    int a_data;
public:
    A(int n):a_data(n){};
};

class B{
private:
    int b_data;
    A a;
public:
    B(int n, A a1):b_data(n),a(a1){};
};

如上代码所示,类B中内嵌了一个对象成员A。如果A类有定义默认的构造函数,则在执行B类的构造函数之前,A对象会自动的调用A类的默认构造函数进行初始化。

相关文章

  • C++ — 类 & 对象超详解

    C++ 类 & 对象 C++ 在 C 语言的基础上增加了面向对象编程,C++ 支持面向对象程序设计。类是 C++ ...

  • C++零基础教程之类和对象初识

    C++ 类和对象 C++ 在 C 语言的基础上增加了面向对象编程,C++ 支持面向对象程序设计。类是 C++ 的核...

  • C++面向对象

    C++类和对象 C++ 在 C 语言的基础上增加了面向对象编程,C++ 支持面向对象程序设计。类是 C++ 的核心...

  • C++面向对象基础(二)

    目录 C++ 基础(一) C++面向对象基础(二) 一、类 C++ 中可以使用 struct、class 来定义一...

  • C++ 类 & 对象

    原文地址:C++ 类 & 对象 C++ 在 C 语言的基础上增加了面向对象编程,C++ 支持面向对象程序设计。类是...

  • CPP基础:面向对象编程

    面向对象编程 类 C++ 在 C 语言的基础上增加了面向对象编程,C++ 支持面向对象程序设计。类是 C++ 的核...

  • C++基础:类与对象一

    作者:慧科集团华东校区-朱家聪老师,转载请注明出处及本链接。 C++的基本语法 include 与C语言中相同,使...

  • cpp面向对象

    面向对象编程 [TOC] 类 C++ 在 C 语言的基础上增加了面向对象编程,C++ 支持面向对象程序设计。类是 ...

  • NDK开发—C++面向对象编程(四)

    类 C++ 在 C 语言的基础上增加了面向对象编程,C++ 支持面向对象程序设计。类是 C++ 的核心特性,用户定...

  • 2022-08-01# 面向对象编程

    类 C++ 在 C 语言的基础上增加了面向对象编程,C++ 支持面向对象程序设计。类是 C++ 的核心特性,用户定...

网友评论

      本文标题:C++基础:类与对象一

      本文链接:https://www.haomeiwen.com/subject/dxrmrxtx.html