Compare commits

...

7 Commits

Author SHA1 Message Date
ec1ebcaed6 comments 2020-05-24 19:17:19 +02:00
f6e6180958 fix 2020-05-24 19:15:22 +02:00
608dafaf85 complete 2020-05-24 19:13:09 +02:00
a0bdd99b3f polymorphism completed 2020-05-24 18:44:11 +02:00
0d55cf1273 polymorphism 2020-05-24 17:39:59 +02:00
804adb3b89 more lessons 2020-05-24 17:04:37 +02:00
5abcc6ed5a init 2020-05-23 19:34:38 +02:00
30 changed files with 463 additions and 4 deletions

6
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,6 @@
{
"files.associations": {
"system_error": "cpp",
"xlocale": "cpp"
}
}

View File

@ -14,13 +14,14 @@ Lessons:
- [instanciating objects, accessing attributes and methods](./lessons/Instances.md)
- [creating a class](./lessons/Classes.md)
- [constructors](./lessons/Constructors.md)
- [encapsulation](./lessons/Encapsulation.md)
- [inheritance](./lessons/Inheritance.md)
- [properties](./lessons/Properties.md)
- [polymorphism](./lessons/Polymorphism.md)
Work in progress:
- inheritance
- encapsulation
- getter / setter / property
- polymorphism
- virtual classes
- interfaces
- Factories
- Generics

5
cpp/Polymorphism.md Normal file
View File

@ -0,0 +1,5 @@
# Polymorphism
Relevant files:
- [main.cpp](./inheritance/main.cpp)

13
cpp/inheritance/README.md Normal file
View File

@ -0,0 +1,13 @@
# Inheritance
c++ also allows to inherit from multiple base classes at once, but that is a
little to complicated for this lesson.
Relevant files:
- [animal.h](./animal.h)
- [animal.cpp](./animal.cpp)
- [cat.h](./cat.h)
- [cat.cpp](./cat.cpp)
- [dog.h](./dog.h)
- [dog.cpp](./dog.cpp)

View File

@ -0,0 +1,11 @@
#include "animal.h"
#include <iostream>
#include <string>
animal::animal(std::string name) {
this->name = name;
}
void animal::make_sound() {
cout << name << ":" << endl;
}

13
cpp/inheritance/animal.h Normal file
View File

@ -0,0 +1,13 @@
#pragma once
#include <string>
using namespace std;
class animal
{
public:
std::string name;
// define make_sound as virtual to allow overriding in subclasses
virtual void make_sound();
animal(std::string name);
};

12
cpp/inheritance/cat.cpp Normal file
View File

@ -0,0 +1,12 @@
#include "cat.h"
#include <iostream>
#include <string>
void cat::make_sound() {
// call the base class function first
animal::make_sound();
// add additional functionality
cout << "meow" << endl;
}

16
cpp/inheritance/cat.h Normal file
View File

@ -0,0 +1,16 @@
#pragma once
#include <string>
// include the animal header
#include "animal.h"
using namespace std;
// make the class inherit from animal
class cat: public animal
{
// include the animal constructor
using animal::animal;
public:
// override the make_sound function
void make_sound() override;
};

10
cpp/inheritance/dog.cpp Normal file
View File

@ -0,0 +1,10 @@
#include "dog.h"
#include <iostream>
#include <string>
void dog::make_sound() {
// implement own functionality
cout << "doggo " << name << " says:" << endl;
cout << "woof!" << endl;
}

16
cpp/inheritance/dog.h Normal file
View File

@ -0,0 +1,16 @@
#pragma once
#include <string>
// include the animal header
#include "animal.h"
using namespace std;
// make the class inherit from animal
class dog: public animal
{
// include the animal constructor
using animal::animal;
public:
// override the make_sound function
void make_sound() override;
};

17
cpp/inheritance/main.cpp Normal file
View File

@ -0,0 +1,17 @@
#include "animal.h"
#include "cat.h"
#include "dog.h"
#include <string>
int main() {
// because cat and dog are subclasses of animal, they can be stored in an array of animals
animal * animals[2] = {
new dog("buster"),
new cat("mittens")
};
for (animal * a : animals)
// when calling the make_sound function, the implementation of the actual class gets called (in this case cat or dog)
a->make_sound();
}

5
java/Polymorphism.md Normal file
View File

@ -0,0 +1,5 @@
# Polymorphism
Relevant files
- [Program.java](./inheritance/Program.java)

View File

@ -0,0 +1,11 @@
public class Animal {
public String name;
public Animal(String name) {
this.name = name;
}
public void make_sound() {
System.out.println(this.name + ":");
}
}

17
java/inheritance/Cat.java Normal file
View File

@ -0,0 +1,17 @@
// make the class cat inherit from Animal
public class Cat extends Animal {
// java requires an explicit constructor when the supertype awaits parameters in the constructor
public Cat(String name) {
// call supertype constructor
super(name);
}
// override make_sound
public void make_sound() {
// optional: call the parent class function
super.make_sound();
// add additional functionality
System.out.println("meow");
}
}

14
java/inheritance/Dog.java Normal file
View File

@ -0,0 +1,14 @@
public class Dog extends Animal {
// java requires an explicit constructor when the supertype awaits parameters in the constructor
public Dog(String name) {
// call supertype constructor
super(name);
}
// override the method make_sound
public void make_sound() {
// implement own functionality
System.out.println("doggo " + this.name + " says:");
System.out.println("woof!");
}
}

View File

@ -0,0 +1,14 @@
public class Program {
public static void main(String[] args) {
// because cat and dog are subclasses of animal, they can be stored in an array of animals
Animal[] animals = {
new Dog("buster"),
new Cat("mittens")
};
for (Animal a : animals) {
// when calling the make_sound function, the implementation of the actual class gets called (in this case cat or dog)
a.make_sound();
}
}
}

View File

@ -0,0 +1,7 @@
# Inheritance
Relevant files:
- [Animal.java](./Animal.java)
- [Cat.java](./Cat.java)
- [Dog.java](./Dog.java)

32
lessons/Encapsulation.md Normal file
View File

@ -0,0 +1,32 @@
# Encapsulation
Encapsulation is a simple lesson, this one is not gonna need any code examples.
There are typically 3 keywords you need for encapsulation: private, protected
and public.
## Private
Private methods and fields are only acessible from within the same class, they
can't be read or written from outside.
## Protected
Protected is just like private, but descendant classes can access them.
## Public
Public is accessible from anywhere.
## The static modifier
Static is another one of those keywords, although it doesn't really control
access to fields and methods. Anything with the static keyword can be used
without an instance of the class. That means you can directly access with with
Class.property instead of creating an instance of that class first. This is used
for example in java for the main method, since it needs to be accessible without
running any of the programs code first.
Encapsulation is not a safety feature, it's only to make clear, which properties
should be used by others. Methods like reflection and directly reading/writing
memory can still access private or protected properties.

15
lessons/Inheritance.md Normal file
View File

@ -0,0 +1,15 @@
# Inheritance
Inheritance is useful to minimize code duplicates and generalize types in base
classes.
A Class can inherit all public and protected functions and fields from a base
class and add its own or override existing ones. Private fields and functions
still exist in the base class, but can't be acessed from the extending class.
## Examples
- [Java](../java/inheritance/README.md)
- [Rust](../rust/Inheritance.md)
- [C++](../cpp/inheritance/README.md)
- [JavaScript (using TypeScript)](../typescript/inheritance/README.md)

19
lessons/Polymorphism.md Normal file
View File

@ -0,0 +1,19 @@
# Polymorphism
Polymorphism is the ability to treat subclasses like their base classes, for
example passing cat, which extends animal to a function that expects an animal
as parameter. or storing objects of different types that all extend a common
class in an array of that common type.
You lose acess to the properties of the subclass, but you can still access the
base class like usual. When the subclass overrides behaviour of the base class,
the overridden functionality in the subclass is still called.
You can regain access to properties of the subclass with casting, but you have
to make sure that the object is actually an instance of that class or you might
run into runtime errors.
- [Java](../java/Polymorphism.md)
- [Rust](../rust/Inheritance.md)
- [C++](../cpp/Polymorphism.md)
- [JavaScript (using TypeScript)](../typescript/Polymorphism.md)

61
lessons/Properties.md Normal file
View File

@ -0,0 +1,61 @@
# Properties
Properties are a way to restrict read/write access to a field and to add
additional verifications, computations or function calls to accessing a field.
To define a property you need one private field that stores your data and the
getter/setter for it. If you don't want it to be readable or writable, you can
leave out either of the accessor functions.
None of the languages featured here have a full implementation of properties.
Languages like c# and Delphi do though.
Delphi has the simplest syntax for properties I've seen so far.
```pas
// this property will read from the field FFoo and write using the function set_foo
property Foo read FFoo write set_foo;
```
C# is a bit more complicated, but still better than the languages here
```cs
public string Foo
{
get => _foo;
set {
_foo = do_something(value);
}
}
```
## Typescript
Typescript allows a somewhat property implementation. In the class itself you
define getter and setter functions using the get and set keywords
```ts
public get foo(): string {
return this._foo;
}
public set foo(val: string): void {
this._foo = do_something(val);
}
```
From the outside, the property can be read and written like in c# and Delphi,
just like working with a variable.
## C++, Java and Rust
Those languages don't provide a property syntax at all, instead you have to
create public functions like set_foo and get_foo to replace them.
## Additional note to rust
Properties don't exist in rust either. But replacing them with getters and
setters is also discouraged. Quoting from a reddit post
`Expose behavior, not state`. That means you should present functions to outside
viewers and not your plain data. An object should be able to do all its intended
functions itself without having an outside observer read or write its data.

6
rust/Inheritance.md Normal file
View File

@ -0,0 +1,6 @@
# Inheritance and Polymorphism
Rust does not allow extending classes. Instead the base class is stored as a
field in the extending class. Polymorphism can then be achieved by passing the
field instead of the whole object to a function. Although casting back to the
advanced class or overriding functions is not possible.

View File

@ -0,0 +1,5 @@
# Polymorphism
Relevant files
- [index.ts](./inheritance/index.ts)

View File

@ -0,0 +1,7 @@
# Inheritance
Relevant files:
- [animal.ts](./animal.ts)
- [cat.ts](./cat.ts)
- [dog.ts](./dog.ts)

View File

@ -0,0 +1,11 @@
export class Animal {
public name: string;
public constructor(name: string) {
this.name = name;
}
public make_sound() {
console.log(`${this.name}:`);
}
}

View File

@ -0,0 +1,13 @@
import {Animal} from './animal';
// make the class cat inherit from Animal
export class Cat extends Animal {
// override make_sound
public make_sound() {
// optional: call the parent class function
super.make_sound();
// add additional functionality
console.log('meow');
}
}

View File

@ -0,0 +1,11 @@
import {Animal} from './animal';
export class Dog extends Animal {
// override the method make_sound
public make_sound() {
// implement own functionality
console.log(`doggo ${this.name} says:`);
console.log('woof!');
}
}

View File

@ -0,0 +1,14 @@
import { Dog } from "./dog";
import { Cat } from "./cat";
import { Animal } from "./animal";
// because cat and dog are subclasses of animal, they can be stored in an array of animals
const animals: Animal[] = [
new Dog('buster'),
new Cat('mittens')
]
for (const a of animals) {
// when calling the make_sound function, the implementation of the actual class gets called (in this case cat or dog)
a.make_sound();
}

View File

@ -0,0 +1,11 @@
{
"name": "ts-oop",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}

View File

@ -0,0 +1,66 @@
{
"compilerOptions": {
/* Basic Options */
// "incremental": true, /* Enable incremental compilation */
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
// "lib": [], /* Specify library files to be included in the compilation. */
// "allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
// "declaration": true, /* Generates corresponding '.d.ts' file. */
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
// "sourceMap": true, /* Generates corresponding '.map' file. */
// "outFile": "./dist", /* Concatenate and emit output to single file. */
"outDir": "./dist", /* Redirect output structure to the directory. */
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
// "composite": true, /* Enable project compilation */
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
// "removeComments": true, /* Do not emit comments to output. */
// "noEmit": true, /* Do not emit outputs. */
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
/* Strict Type-Checking Options */
"strict": true, /* Enable all strict type-checking options. */
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* Enable strict null checks. */
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
/* Additional Checks */
// "noUnusedLocals": true, /* Report errors on unused locals. */
// "noUnusedParameters": true, /* Report errors on unused parameters. */
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
/* Module Resolution Options */
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
// "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
/* Source Map Options */
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
/* Experimental Options */
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
/* Advanced Options */
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
}
}