C++ 类

C结构体、C++结构体、C++中类

C语言中的struct中只能定义成员变量,不能定义成员函数,可以定义函数指针; 所以C中的struct可以看作是一个复杂的数据类型,不能用于面向对象编程。

C++中的struct既可以定义成员变量也可以定义成员函数;

C中声明结构体变量的时候struct关键字不能省,C++中可以省略。

C++中class跟struct的区别是类中成员默认是私有的,struct默认是公有的。C++中struct也可以继承。

C中struct的定义和使用:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

struct A
{
    int a;
    char*p;
};

void main()
{   
    struct A A_obj;
    A_obj.a = 10;
    A_obj.p = "Hello!";
    printf("%d\n",A_obj.a);    
    printf("%s\n",A_obj.p);
    return;
}

 

static

C中的static的作用是限定作用域和保持变量内容持久化

关键字static定义的变量位于静态存储区,在整个程序执行期间会一值存在,即便是在局部区域定义的static变量也不会随着退出局部作用域而销毁,而是保持当前变量值,直到再次对该作用域访问,就可以恢复static变量值。 但static并不改变变量的作用域,局部定义的static变量只能在当前作用域内访问,全局不可见。

C++中类中的static定义一个所有对象共享的成员必须在类外初始化(static变量是独立于类的),并且在使用前必须初始化,任何成员函数(普通函数和静态函数)都可以访问公有static成员变量。

对于私有静态成员,可以通过公有静态成员函数访问。

类中也可以定义static静态函数,但静态函数不属于任何类,没有指向本对象的this指针,也就区分不出各个对象不同的成员变量,所以static函数不能访问非static成员变量。

C++中类的成员变量可以定义成const的,但是const成员变量必须在初始化列表里边初始化。

类也可以访问静态方法,调用格式是 A::func();

#include<iostream>
using namespace std;

class A
{
    public:
    int a;
    static int count;
    static int get1(){
        return count;
    }
    /*static int get2(){
        return a;  //编译错误,静态函数不能访问非静态成员变量
    }*/
};

int A::count =10;

int main()
{   
    A A_obj;
    A_obj.a = 10;
    A_obj.count = 10;   
    cout<<A_obj.a<<endl;
    cout<<A_obj.count<<endl;
    cout<<A_obj.get1()<<endl;
    cout<<A::get1()<<endl;
    //cout<<A_obj.get2()<<endl;  //编译错误,静态函数不能访问非静态成员变量
    return 0;
}


构造函数不可以是虚函数,析构函数可以是虚函数

构造函数做包括分配内存空间等的初始化工作,未完成前,表示虚函数指针也还没有建立起来,不可能存在虚函数。

构造函数在构建对象时,必须确切知道对象的类型,不可能在使用时候再分配对象的属性,所以构造函数也不需要是虚函数。

析构函数可以是虚函数主要是考虑到在实现多态时,当用基类操作派生类,在析构时防止仅仅析构基类而不析构派生类的状况发生。所以对于不同的对象,调用不同的析构实现。


C++ 函数重载和运算符重载

函数重载:在同一个作用域内,可以声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同。但是不能仅通过返回类型的不同来区分重载函数。

运算符重载:普通运算符用于基本类型的算术运算、赋值等操作,但是执行两个类对象的运算该怎么操作呢,比如如何判定类A“=”类B?以及两个类对象相加怎么定义?这种情况就需要运算符重载了,即重新定义运算符操作,按既定要求进行运算。运算符重载为类而生。

重载运算符有一个返回类型和一个参数列表,由关键字operator+要重载的运算符号构成:

Box operator+(const Box&);

以上可以类比普通函数的定义,返回类型是Box类对象,函数名称是“operator+”,表示这是一个“+”号重载,参数是Box类对象的引用。
“+”运算符重载示例:

#include <iostream>
using namespace std;

class Box
{
public:
    void get_num(){
        cout<<count<<endl;
    }
    void set_num(int amount){
        count = amount;
    }
    
    Box operator+(const Box&other){
        Box box;
        box.count = this->count+other.count;
        return box;
    }
private:
    int count;
};

int main()
{
Box box1,box2,box3;
box1.set_num(1);
box2.set_num(2);
box3 = box1+box2;
box3.get_num();
return 0;
}

 

C++类默认生成的4个函数

  1.     默认构造函数:A(void),无参构造函数
  2.     拷贝(复制)构造函数:A(const A&a)。用一个对象A去为另一个对象赋值。
  3.     析构函数:~A(void)。释放掉A所占用的空间。
  4.     赋值函数:A &original = const A&a。使用一个对象a直接为另一个对象赋值。

拷贝(复制)构造函数
对象的复制是在B对象创建的时候,将对象A的状态全部复制过来,复制操作是 “类名 B(A)” 或“类名 B = A”。 作用是用已有的对象A去克隆出新对象B,使用场合是在创建一个新的对象时。

赋值构造函数
一个类定义了两个对象A和B,可以使用A对B对象赋值,这样B对象中所有数据成员的值就跟A中一样了,赋值操作是 "B = A" ,使用场合是在两个对象都已经存在的情况下。

赋值操作过程是将一个对象的数据成员在存储空间的状态复制到另一个对象的数据成员的存储空间中。对象的赋值是在两个已经存在的对象上进行的。“赋值”是对象成员变量之间的赋值。

默认的拷贝函数和赋值函数都是采用“值”操作的,按照字面值复制,当成员变量使用了堆空间(指针)时,就会导致两个对象操作同一块内存的问题,这就是“浅拷贝”。

要实现深拷贝,需要自己定义拷贝函数和赋值函数。

 

delete[] a 和delete a

对于内部数据类型,不管是单个指针还是数组指针使用 delete a 都可以正确释放内存。

对于类对象数组,如 A *a = new A[10]; 需要使用delete[] a分别调用A类的10个对象的析构函数分别释放内存,如果使用 delete a,只会调用第一个对象的析构函数,剩下9个对象的内存空间得不到释放,造成内存泄漏。

 

实现String类的构造函数、析构函数、赋值函数、拷贝构造函数

#include <iostream>
using namespace std;

class String
{
public:
    String(const char* str=NULL);  //普通构造函数
    String(const String &other);   //复制构造函数
    ~String(void);   //析构函数
    String& operator= (const String &other);  //赋值函数
    void print(){
        cout<<my_date<<endl;   //验证函数
    }
private:
    char *my_date;
};

String::~String(void){
    delete[] my_date;   //析构函数,释放内存
}

String::String(const char* str){  //构造函数
    if(str==NULL)
    {
        my_date = new char[1];
        *my_date = '\0';
    }
    else
    {
        my_date = new char[strlen(str)+1];
        strcpy(my_date,str);
    }

}

// 赋值构造函数
String& String::operator=(const String&other){
    if(this==&other){
        return *this;
    }
    delete my_date;  //赋值时候当前对象已经存在,需要先释放
    my_date = new char[strlen(other.my_date)+1];
    strcpy(my_date,other.my_date);
    return *this;
}

//拷贝(复制)构造函数
String::String(const String &other){
    my_date = new char[strlen(other.my_date)+1];
    strcpy(my_date,other.my_date);
}
 
int main ()
{
    String A("HELLO"); //调用构造函数
    String B = A;  //调用拷贝构造函数
    String C("WORLD");
    C = A; //调用赋值构造函数
    A.print(); //验证    
    B.print(); //验证    
    C.print(); //验证    
        return 0;  //return 之前调用析构函数
}

 

虚函数和纯虚函数

C++的虚函数主要作用是实现“运行时多态”,父类中提供虚函数的实现,为子类提供默认的函数实现,子类也可以重写虚函数。

纯虚函数:纯虚函数是在基类中只有该函数的声明,没有具体实现,格式为:

virtual void out1(string s)=0;  //加 “=0”

纯虚函数“只提供申明,没有实现”,对子类是“接口继承”,纯虚函数也是一种“运行时多态”。
包含纯虚函数的类,被称为是“抽象类”。不能从抽象类中用new实例化出一个对象,只有实现了这个纯虚函数的功能的子类才能new出对象。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值