C++ 面向对象

声明与定义

如果要声明一个类,标准的做法是声明同名的.h.cpp文件。

  • .h 存放类的的声明(比如类方法的入参,返回值类型的声明等)
  • .cpp 存放类的定义(比如类方法的具体实现)

存放类实现的.cpp必须include对应的声明文件.h,比如car.cpp必须在开头引入#include "car.h".

使用类的地方也需要include对应的声明文件.h,比如people.cpp要使用car对象的方法必须在开头也引入#include "car.h".

为什么要分开存放.h.cpp

基于模块化的方式考虑,接口实现与接口定义是分开的。另外,分开也可以减少编译器的工作量,至于为什么,你得去了解C++的编译器了。

一般标准库大多采用.h.cpp分离的方式去写的。

enum

枚举类是为了定义一个较小集合同类常量,防止常量误用,可读性也更强。

#include <iostream>
using namespace std;

enum class Color{
    red,blue,green

};
Color& operator++(Color& t)
// prefix increment: ++
{
    switch (t) {
        case Color::red:
            return t = Color::blue;
        case Color::blue:
            return t = Color::green;
        case Color::green:
            return t = Color::red;
    }
}
ostream &operator<<(ostream &output,Color& t)
// prefix increment: ++
{
    switch (t) {
        case Color::red:
            output<< "red";
            return output ;
        case Color::blue:
            output<< "blue";
            return output ;
        case Color::green:
            output<< "green";
            return output ;
    }
}

int main(){
    // 输出枚举类的int值
    cout<< (int)Color::red << endl;   // => 0
    cout<< (int)Color::blue << endl;  // => 1
    // 比较枚举类
    if (Color::red > Color::blue){
        cout<< "red is great than blue" << endl;
    }else{
        cout<< "blue is great than red" << endl;  // this is right
    }
    // 默认枚举类,只有==,<等操作符,要想定义更多,得用运算符重载
    Color t= Color::red;
    cout<< ++t << endl;

}

输出:

0
1
blue is great than red
blue

对象

因为面向对象学的主要是Java,所以以Java的视角来看待C++的面向对象实现。

对象和指针的区别

我看一个人写的还挺好:C++类对象和类指针的区别

静态方法和成员方法

和Java不同,c++允许对象引用调用静态方法。但是和Java相同的是,不能利用静态方法使用成员变量。

class List{
public:
    string hello(List& a);
    static string hello();
    int sample=0;
};
// 成员方法
string List::hello(List& a) {
    cout<< "static sample"<< this->sample << endl;  // => allowed
    return "hello world";
}
// 静态方法
string List::hello() {
   // cout<< "static sample"<< this->sample << endl;   // =>not allowed
    return "hello world 2";
}


int main (){
    List a;
    cout<< "greeting:"<< a.hello(a) << endl;
    cout<< "greeting:"<< a.hello() << endl;
}

对象的生命周期

以下使用Circle对象为例子,C++的对象分配分成两种情况:

  1. 类对象分配函数栈,超出作用域,自动释放。
  2. 类指针指向的对象分配在堆中,需要手动释放(free or delete)。
class Shape{
public:
    int simple;
    virtual string hello() = 0;
};



class Circle: public Shape{
public:
    Circle(){
        cout<<"I am created"<<endl;
        simple=0;
    }
    string hello() {
        return "hello";
    }
    ~Circle(){
        cout<< "I am killed" << endl;
    }
};

void func1(){
    // Circle c,类对象,因为在栈上分配,函数执行完,内存就被回收了,执行了析构函数
    cout<< "---------func1--------------" << endl;
    Circle c;
    cout<< c.hello() << endl;
}
void func2(){
    // Circle c,类对象,因为在堆上分配,函数执行完,内存不会自动回收,需要使用delete语句手动释放其内存
    cout<< "---------func2--------------" << endl;
    Circle* c=new Circle();
    cout<<c->hello()<<endl;
    delete c;
}

int main() {
    func1();
    func2();
    return 0;
}

输出:

I am created
hello
I am killed
---------func2--------------
I am created
hello
I am killed

拷贝构造函数

参考:C++拷贝构造函数(复制构造函数)详解

拷贝构造函数分成三种情况:

  1. 初始化的时赋值语句
  2. 作为函数形参传递入函数
  3. 作为函数返回值返回
1. 第一种情况:初始化的时赋值语句
class Arr {
public:
    int* list;
    Arr();
};

Arr::Arr() {
    cout<< "I am created"<<endl;
    this->list=new int[10];
    for(int* p=list,i=0;p< list+10; p++,i++){
        *p=i;
    }
}


int main() {
    Arr s;
    Arr t =s; // 初始化的时赋值语句 
    //Arr t(s); // 等价于 Arr t =s;
    cout<< "list[0]="<<t.list[0] << endl;
    t.list[0]=110;
    cout<< "after t changed the first element,s[0] is changed to :"<< s.list[0] << endl;
}

这里会调用默认的复制构造函数,将对象成员一对一拷贝过去,在这个例子中,只是将指针拷贝了一份,但是数组的内存还是一份。

move函数

防止内存拷贝

int main() {
    vector<int> t;
    t.push_back(112);

    cout << "t[1]:" <<" value="<< t[0] << " address=" << &t[1] << endl;
    vector<int> m = move(t);
    cout << "m[1]:" <<" value= "<< m[0] << " address=" << &m[1] << endl;

}

输出:

t[1]: value=112 address=0x6e1774
m[1]: value= 112 address=0x6e1774

可以看到move前后元素的内存地址并没有发生改变。

vector<int> func2() {
    vector<int> t;
    t.push_back(112);
    cout << "t[1]:" << " value=" << t[0] << " address=" << &t[1] << endl;
    return t;  // 默认执行move
}

int main() {
    vector<int> m = func2();
    cout << "m[1]:" << " value= " << m[0] << " address=" << &m[1] << endl;

}

这里的内存地址m和t也是一样的。

虚析构函数

C++ 对象基类和子类都定义了析构函数,但不是虚析构函数。使用基类指针指向子类,用基类指针删除子类对象时,只会调用基类的析构函数。

C++ 对象基类和子类都定义了析构函数,都是虚析构函数。使用基类指针指向子类,用基类指针删除子类对象时,这种情况才会先调用子类的析构函数,再调用基类的析构函数。

Reference List

  1. https://www.geeksforgeeks.org/c-plus-plus/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值