OpenGATE Retro Blog |
C++ im Vergleich zu RUSTEinleitungMir wurde kürzlich ein 3-tägiger Rust-Crashkurs angeboten, um die
Programmiersprache kennen zu lernen. So kann man direkt die Syntax vergleichen. Schließlich sagt ein Code mehr tausend Wort. Hello WorldFunktionen und ParameterObjekte
1//C++ 2class Thing 3{ 4private: 5 int m_foo; 6 int m_bar; 7public: 8 Thing(int foo) 9 : m_foo(foo), 10 m_bar(0) 11 { 12 } 13 static char const* get_type_description() 14 { 15 return "This is a Thing type."; 16 } 17 int get_foo() const 18 { 19 return this->m_foo; 20 } 21 int get_bar() const 22 { 23 return this->m_bar; 24 } 25 void set_bar(int value) 26 { 27 m_foo = value; 28 } 29}; 30int use_thing() 31{ 32 int foo = 12; 33 Thing thing(foo); 34 thing.set_bar(13); 35 int n = thing.get_foo() + thing.get_bar(); 36 printf("n = %d\n", n); 37 return 0; 38}
1//Rust 2struct Thing { 3 m_foo: i32, 4 m_bar: i32 5} 6 7impl Thing { 8 pub fn new(foo: i32) -> Self { 9 // return a new constructed Thing 10 Self { 11 m_foo: foo, 12 m_bar: 0 13 } 14 } 15 pub fn get_type_description() -> &'static str { 16 // return a static immutable string reference 17 "This is a Thing type." 18 } 19 20 pub fn get_foo(&self) -> i32 { 21 // does not mutate object 22 // full return statement 23 return self.m_foo; 24 } 25 pub fn get_bar(&self) -> i32 { 26 // does not mutate object 27 // short return statement 28 self.m_bar 29 } 30 pub fn set_bar(&mut self, bar: i32) { 31 // mutates object 32 self.m_bar = bar; 33 } 34} 35 36pub fn use_thing() { 37 let foo = 12; 38 let mut thing = Thing::new(foo); 39 thing.set_bar(13); 40 let n = thing.get_foo() + thing.get_bar(); 41 println!("Description = {}", Thing::get_type_description()); 42 println!("n = {}", n); 43} 44 InterfacesIn C++ werden Schnittstellen und Polymorphismus durch virtuell Methoden in Klassen definiert. Implementiert werden Schnittstellen dann durch Ableitung einer neuen Klasse von der Interface-Klasse. 1class Animal 2{ 3public: 4 virtual ~Animal() {} 5 virtual std::string get_name() const = 0; 6 virtual void speak() const = 0; 7}; 8class Cat : public Animal 9{ 10private: 11 std::string m_name; 12public: 13 Cat(char const* name) 14 : m_name(name) 15 { 16 } 17 std::string get_name() const override 18 { 19 return m_name; 20 } 21 void speak() const override 22 { 23 printf("Meow\n"); 24 } 25}; 26class Dog : public Animal 27{ 28private: 29 std::string m_name; 30public: 31 Dog(char const* name) 32 : m_name(name) 33 { 34 } 35 std::string get_name() const override 36 { 37 return m_name; 38 } 39 void speak() const override 40 { 41 printf("Meow\n"); 42 } 43}; 44static void talk_with_animal(Animal const& animal) 45{ 46 std::cout << "Animals's name is: " << animal.get_name(); 47 animal.speak(); 48} 49 50void handle_animals() 51{ 52 Cat c("Kitty"); 53 Dog d("Sparky"); 54 55 talk_with_animal(c); 56 talk_with_animal(d); 57} In Rust kann jede Struktur über das 1pub trait Animal { 2 fn get_name(&self) -> String; 3 fn speak(&self); 4} 5 6struct Cat { 7 m_name: String 8} 9 10impl Cat { 11 pub fn new(name: &str) -> Self { 12 Self { 13 m_name: name.to_string() 14 } 15 } 16} 17 18impl Animal for Cat { 19 fn get_name(&self) -> String { 20 self.m_name.clone() 21 } 22 fn speak(&self) { 23 println!("Meow"); 24 } 25} 26 27struct Dog { 28 m_name: String 29} 30 31impl Dog { 32 pub fn new(name: &str) -> Self { 33 Self { 34 m_name: name.to_string() 35 } 36 } 37} 38 39impl Animal for Dog { 40 fn get_name(&self) -> String { 41 self.m_name.clone() 42 } 43 fn speak(&self) { 44 println!("Woof"); 45 } 46} 47 48fn talk_with_animal(animal: &dyn Animal) { 49 println!("Animals's name is: {}", animal.get_name()); 50 animal.speak(); 51} 52 53pub fn handle_animals() { 54 let c = Cat::new("Kitty"); 55 let d = Dog::new("Sparky"); 56 57 let a: &dyn Animal = &c; 58 talk_with_animal(a); 59 60 let a: &dyn Animal = &d; 61 talk_with_animal(a); 62} 63 Operatoren für TypenIn C++ können für alle (nicht-primitiven) Typen Operatorfunktionen überladen
werden. Somit lassen sich Objekte mit 1//C++ 2struct Point 3{ 4 float x; 5 float y; 6 7 Point(float xx, float yy) 8 : x(xx), y(yy) 9 { 10 } 11} 12 13Point operator+(Point const& l, Point const& r) 14{ 15 return Point(l.x + r.x, l.y + r.y); 16} 17Point& operator+=(Point& l, Point const& r) 18{ 19 l.x += r.x; 20 l.y += r.y; 21 return l; 22} 23 24Point operator-(Point const& l, Point const& r) 25{ 26 return Point(l.x - r.x, l.y - r.y); 27} 28Point& operator-=(Point& l, Point const& r) 29{ 30 l.x -= r.x; 31 l.y -= r.y; 32 return l; 33} 34 35Point operator*(Point const& l, float const& factor) 36{ 37 return Point(l.x * factor, l.y * factor); 38} 39Point& operator*=(Point& l, float const& factor) 40{ 41 l.x *= factor; 42 l.y *= factor; 43 return l; 44} 45 46Point operator/(Point const& l, float const& denominator) 47{ 48 return Point(l.x / denominator, l.y / denominator); 49} 50Point& operator/=(Point& l, float const& denominator) 51{ 52 l.x /= denominator; 53 l.y /= denominator; 54 return l; 55} 56 In Rust werden Operatoren durch Traits implementiert.
Diese liegen in 1// Rust 2use std::ops::Add; 3use std::ops::AddAssign; 4use std::ops::Sub; 5use std::ops::SubAssign; 6use std::ops::Mul; 7use std::ops::MulAssign; 8use std::ops::Div; 9use std::ops::DivAssign; 10 11// struct must derive Copy and Clone, 12// otherwise operator parameters are consumed and cannot be used again 13#[derive(Copy, Clone)] 14pub struct Point { 15 pub x: f32, 16 pub y: f32 17} 18 19impl Point { 20 pub fn new(x: f32, y: f32) -> Self { 21 Self { 22 x: x, 23 y: y 24 } 25 } 26} 27 28impl Add for Point { 29 type Output = Point; 30 fn add(self, other: Self) -> Self::Output { 31 Point::new(self.x + other.x, self.y + other.y) 32 } 33} 34impl AddAssign for Point { 35 fn add_assign(&mut self, other: Self) { 36 self.x += other.x; 37 self.y += other.y; 38 } 39} 40impl Sub for Point { 41 type Output = Self; 42 43 fn sub(self, other: Self) -> Self::Output { 44 Point::new(self.x - other.x, self.y - other.y) 45 } 46} 47impl SubAssign for Point { 48 fn sub_assign(&mut self, other: Self) { 49 self.x -= other.x; 50 self.y -= other.y; 51 } 52} 53impl Mul<f32> for Point { 54 type Output = Self; 55 56 fn mul(self, factor: f32) -> Self::Output { 57 Point::new(self.x * factor, self.y * factor) 58 } 59} 60impl MulAssign<f32> for Point { 61 fn mul_assign(&mut self, factor: f32) { 62 self.x *= factor; 63 self.y *= factor; 64 } 65} 66impl Div<f32> for Point { 67 type Output = Self; 68 69 fn div(self, denominator: f32) -> Self::Output { 70 Point::new(self.x / denominator, self.y / denominator) 71 } 72} 73impl DivAssign<f32> for Point { 74 fn div_assign(&mut self, denominator: f32) { 75 self.x /= denominator; 76 self.y /= denominator; 77 } 78} 79 80pub fn use_point_operators() { 81 let p1 = Point::new(1.0, 2.0); 82 let p2 = Point::new(2.0, 3.0); 83 84 let p3 = p1 + p2; 85 assert_eq!(p3.x, p1.x + p2.x); 86 assert_eq!(p3.y, p1.y + p2.y); 87 88 let p4 = p2 - p1; 89 assert_eq!(p4.x, p2.x - p1.x); 90 assert_eq!(p4.y, p2.y - p1.y); 91 92 let p5 = p2 * 10.0; 93 assert_eq!(p5.x, p2.x * 10.0); 94 assert_eq!(p5.y, p2.y * 10.0); 95 96 let p6 = p5 / 5.0; 97 assert_eq!(p6.x, p5.x / 5.0); 98 assert_eq!(p6.y, p5.y / 5.0); 99} Fortsetzung folgt |