OOP基本概念对比:RUST与CPP

本文转自:OOP基本概念对比:RUST与CPP

对象封装

一般来说,一个对象,具有如下性质:
  • 一个区别于其他对象的名字
  • 若干个属性(数据,或字段)
  • 若干个行为(函数,或方法)

在C++中,使用public和private关键字来暴露或者保护对象内部的实现

//C++
#include <iostream>
#include <string>
using namespace std;
//类定义
class Person
{
public:
    Person(string&& name,int salary) : name(name), salary(salary) {};
public://公共字段
    string name;//公共属性
    void SayHi() { cout << name << ":hi" <<endl; };//公共方法
private://私有字段
    int salary;//私有属性
    void Sleep() { cout << "sleep"; };//私有方法
};
int main()
{
    //在栈上创建对象
    Person bobFromStack("Bob",233);
    //在堆上创建对象
    auto pAliceFromheap = new Person("Alice",234);
    bobFromStack.SayHi();
    pAliceFromheap->SayHi();
    system("pause");
    return 0;
}

在Rust中,所有名字默认是private的,只能在当前文件中访问,如果要将名字暴露给外部,需要使用pub关键字

路径用于引用模块树中的项 - Rust 程序设计语言 中文版 (rustwiki.org)

//Rust
pub struct Person {//导出结构体名
  pub name:String,//可供其他模块访问的公共字段
  salary:i32,//仅能在本文件中访问的私有字段
}

impl Person {//为结构体实现方法
  pub fn SayHi(&self) {//可供其他模块访问的公共方法
      println!("{}:Hi",self.name);
  }
  fn Sleep(&self){//仅能在本文件中访问的私有方法
    println!("Sleep");
  }
}

fn main() {
  //在栈上创建对象
  let bobFromStack = Person{name: String::from("Bob"),salary:233,};
  //在堆上创建对象
  let aliceFromHeap = Box::new(Person{name: String::from("Alice"),salary:234,});
  bobFromStack.SayHi();
  aliceFromHeap.SayHi();
}

继承

//C++
class Worker: public Person {
  public:
    string company;
};
//RUST没有继承,使用组合而非继承来复用代码
// https://rustwiki.org/zh-CN/book/ch17-01-what-is-oo.html
/* 近来继承作为一种语言设计的解决方案在很多语言中失宠了,因为其时常带有共享多于所需的代码的风险。子类不应总是共享其父类的所有特征,但是继承却始终如此。如此会使程序设计更为不灵活,并引入无意义的子类方法调用,或由于方法实际并不适用于子类而造成错误的可能性。某些语言还只允许子类继承一个父类,进一步限制了程序设计的灵活性。 */

多态

C++函数重载

重载是指不同参数的静态函数可以使用相同的函数名

int Add(int i1, int i2)
{
    return i1 + i2;
}
int Add(int i1, int i2, int i3)
{
    return i1 + i2 + i3;
}

C++虚函数重写

重写是指子类重新实现了父类中的虚函数

class Base{
//使用virtual关键字定义虚函数
virtual void fun(int a){cout<<"1"<<endl;}
//纯虚函数
virtual void fn()=0;
};

class Derive: Base{
//重写父类中的虚函数
void fun(int a){cout<<"2"<<endl;}
};

C++非虚函数重定义

重定义是指子类重新实现了父类中的非虚函数

class Base{

//非虚函数fun
 void fun(int a){cout<<"1"<<endl;}
};

class Derive: Base{
//名字与父类相同,仍为fun
void fun(int a,int b){cout<<"2"<<endl;}
};

RUST为类型实现Trait

Trait抽象了类的接口,只要是实现了对应Trait的任意类型,都将拥有接口所描述的特性,类比C++中的某些概念,Trait中的方法可以被沿用(类似于继承)或者重新实现(类似于重定义)

另外,如果在Trait中只提供声明不提供实现,那么实现该Trait的类型必须提供该声明的定义(类似于必须将纯虚函数实例化)

RUST不提供重载,如果要支持不同参数的同名函数,考虑使用泛型、tuple、Trait之间的互相配合

trait:定义共享的行为 - Rust 程序设计语言 中文版 (rustwiki.org)

pub struct Person {//导出结构体名
  pub name:String,//可供其他模块访问的公共字段
  salary:i32,//仅能在本文件中访问的私有字段
}

impl Person {//为结构体实现方法
  pub fn SayHi(&self) {//可供其他模块访问的公共方法
      println!("{}:Hi",self.name);
  }
  fn Sleep(&self){//仅能在本文件中访问的私有方法
    println!("Sleep");
  }
}

struct Robot{
  name:String,
}

pub trait SayHello {
  //提供了默认实现的的行为
  fn sayHello(&self){
    println!("Default Hello")
  }
  //未提供默认实现的行为,必须实现该行为才能使用本特征
  fn mustSaySometing(&self);
}

impl SayHello for Person{
  //sayHello覆盖默认行为
  fn sayHello(&self){
    println!("{}:Hello",self.name)
  }
  //实现mustSaySometing
  fn mustSaySometing(&self){println!("Wtf?")} 
}

impl SayHello for Robot{
  //sayHello沿用默认行为
  //实现mustSaySometing
  fn mustSaySometing(&self){println!("Calm down!")} 
}

fn main() {
  
  let bob = Person{name: String::from("Bob"),salary:233,};
  let alice = Robot{name: String::from("alice"),};
  
  bob.sayHello();//Bob:Hello
  alice.sayHello();//Default Hello
  
  bob.mustSaySometing();//Wtf?
  alice.mustSaySometing();//Calm down!
}  

统一接口调用

在C++中,如果想调用多个对象的某个同名方法,不需要针对每个对象都写一次调用,利用虚函数即可

#include <iostream>
#include <string>
#include <vector>

using namespace std;

class Person
{
public:
    Person(string&& name,int salary) : name(name), salary(salary) {};
public:
    string name;
    virtual void SayHi() { cout << name << ":hi" <<endl; };
private:
    int salary;
    void Sleep() { cout << "sleep"; };
};

class Worker :public Person
{
public:
    Worker(string&& name, int salary,string&& company) :Person(move(name),salary),company(company) {};
public:
    string company;
    void SayHi() { cout << company << " " << name << ":hi" << endl; };
};

int main()
{
    vector<Person*> vec;
    auto bob = new Person("Bob",233);
    auto alice = new Worker("Alice", 233, "Bili");
    vec.push_back(bob);
    vec.push_back(alice);
    for (auto& item:vec)
    {//当父类指针指向子类对象时,针对虚函数会分别调用子类中的方法
        item->SayHi();
    }
    system("pause");
    return 0;
}

而在RUST中,想要统一调用某个特定名字的方法,需要用到Trait Object的概念

为使用不同类型的值而设计的 trait 对象 - Rust 程序设计语言 中文版 (rustwiki.org)

特征对象 - Rust语言圣经(Rust Course)

pub struct Person {//导出结构体名
  pub name:String,//可供其他模块访问的公共字段
  salary:i32,//仅能在本文件中访问的私有字段
}

impl Person {//为结构体实现方法
  pub fn SayHi(&self) {//可供其他模块访问的公共方法
      println!("{}:Hi",self.name);
  }
  fn Sleep(&self){//仅能在本文件中访问的私有方法
    println!("Sleep");
  }
}

struct Robot{
  name:String,
}

pub trait SayHello {
  //提供了默认实现的的行为
  fn sayHello(&self){
    println!("Default Hello")
  }
  //未提供默认实现的行为,必须实现该行为才能使用本特征
  fn mustSaySometing(&self);
}

impl SayHello for Person{
  //sayHello覆盖默认行为
  fn sayHello(&self){
    println!("{}:Hello",self.name)
  }
  //实现mustSaySometing
  fn mustSaySometing(&self){println!("Wtf?")} 
}

impl SayHello for Robot{
  //sayHello沿用默认行为
  //实现mustSaySometing
  fn mustSaySometing(&self){println!("Calm down!")} 
}

fn main() {
  let bob = Person{name: String::from("Bob"),salary:233,};
  let alice = Robot{name: String::from("alice"),};
 //使用Trait Object来存储实现了相同Trait的不同类型
  let items:Vec<Box<dyn SayHello>> = vec![
    Box::new(Person{name: String::from("Bob"),salary:235,}),
    Box::new(Robot{name: String::from("alice"),}),
  ];
 //调用不同类型中的同一个方法
  for item in items {
      item.mustSaySometing();
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值