Шнековая соковыжималка для томатов ручная

Ремонт

Шнековая соковыжималка для томатов ручная

Если вы ищете надежный способ получения томатного сока, ручная шнековая соковыжималка станет отличным выбором. Она работает без электричества, что делает её универсальной для использования на даче, в походе или в любом месте, где нет доступа к розетке. Модели с шнековым механизмом эффективно отжимают сок, оставляя минимум отходов, а их простая конструкция обеспечивает долгий срок службы.

Одним из ключевых преимуществ ручной соковыжималки для томатов является её высокая производительность. Шнек медленно вращается, что позволяет максимально извлечь сок, не разрушая структуру мякоти. Это особенно важно для томатов, так как их текстура требует бережного обращения. В результате вы получаете насыщенный сок с минимальным количеством пены и осадка.

Ещё один плюс – простота в уходе. Большинство моделей легко разбираются, что упрощает процесс мытья. Детали обычно изготавливаются из безопасных материалов, таких как нержавеющая сталь или пищевой пластик, что делает их пригодными для работы с продуктами. Кроме того, ручные соковыжималки компактны и не занимают много места на кухне.

Если вы часто готовите томатный сок дома, обратите внимание на модели с регулируемым фильтром. Это позволит вам контролировать консистенцию сока, выбирая между густым напитком с мякотью или более жидким вариантом. Такая универсальность делает ручную шнековую соковыжималку незаменимым помощником на кухне.

Ручная шнековая соковыжималка для томатов: обзор и преимущества

Выбирайте ручную шнековую соковыжималку, если хотите получить максимально насыщенный и густой томатный сок. Такие модели работают на основе медленного вращения шнека, что позволяет бережно отжимать сок, сохраняя все полезные вещества и не нагревая мякоть.

Основные преимущества

Основные преимущества

Качество сока: Ручные шнековые соковыжималки отжимают сок без нагрева, что сохраняет витамины, минералы и естественный вкус томатов. Сок получается густым, с минимальным количеством жмыха.

Простота использования: Для работы не требуется электричество. Достаточно загрузить томаты в устройство и крутить ручку. Это делает соковыжималку идеальной для использования на даче или в походных условиях—

Читайте также:  Кухня гостиная в маленькой квартире дизайн

date: «2019-06-23»

# 12 | 面向对象之继承:继承是代码复用的合理方式吗?

你好,我是吴咏炜。

在上一讲里,我们讨论了面向对象的第一个特点,封装。今天,我们继续来讲第二个特点:继承。

## 什么是继承?

继承是面向对象编程语言中的一个重要机制。通过继承,一个对象可以使用另一个对象的代码,从而实现代码复用。

C加加 的继承机制有一个发展过程。在最早的 C 语言里,我们经常会写类似下面的代码:

cpp

struct employee {

int id;

const char* name;

int age;

double salary;

};

struct manager {

struct employee base;

const char group;

int group_size;

};

在这段代码里,`manager` 对象通过把 `employee` 对象放在第一个成员的位置,就自动继承了 `employee` 的全部成员。在需要 `employee` 的地方使用 `manager` 也是可以的,因为 `manager` 的第一个成员就是 `employee` 对象。从某种角度,这已经是一种继承机制了。

在 C加加 中,标准的选择是把继承直接作为一种语言机制来提供。上面的代码在 C加加 里可以简单地写成:

cpp

struct manager : employee {

const char group;

int group_size;

};

看起来更简洁了,不是?当然,上面的代码只是默认情况。我们通常还是应该写上 `public` 来表示继承关系的:

cpp

struct manager : public employee {

const char group;

int group_size;

};

## 继承的基本语法

在 C加加 里,你需要像下面这样来写继承:

cpp

class 派生类名 : 访问说明符 基类名 {

成员定义……

};

其中的“访问说明符”跟上一讲中我们提到的相同,可以出现零次或一次,表示从基类继承的成员在派生类中的最大访问权限(如果出现零次,在类定义中默认是 `private`,在结构体定义中默认是 `public`)。我们通常应该使用 `public` 继承,表示基类的 public 成员在派生类中还是 public 的;其他访问说明符极少使用,你只要知道它们的存在就够了。

跟其他面向对象编程语言不同,C加加 支持多继承。也就是说,一个类可以同时从多个类继承。这时候的语法是:

cpp

class 派生类名 :

访问说明符 基类名1,

访问说明符 基类名2,

访问说明符 基类名3 {

成员定义……

};

多继承会带来很多复杂的麻烦,我们后面再具体讨论。

### 成员函数的重载、覆盖和隐藏

继承的基本使用非常简单,不过,里面有一些细节需要注意。

作为一个例子,我们先定义一个 `Base` 类:

cpp

class Base {

public:

void f(int);

void f(double);

void g(int i = 10);

};

我们然后定义一个 `Derived` 类:

cpp

class Derived : public Base {

public:

void h();

void f(int);

};

`Derived` 类继承自 `Base` 类,并额外定义了一个 `h` 成员函数,同时重定义了一个 `f` 成员函数。注意,我们这儿说的是重定义,而不是重载。为了说清楚重载、覆盖和隐藏这些概念的区别,我们需要仔细分析一下。

重载(overload)发生在同一个类或名字空间里,函数名相同但参数类型不同的函数之间的关系。在上面的 `Base` 类里,`f(int)` 和 `f(double)` 就是一对重载函数。

覆盖(override)一般发生在继承关系中。一个派生类中定义的函数如果和基类中定义的虚函数有相同的函数签名(函数名、参数类型、`const`/`volatile` 修饰符),那这个派生类的函数就覆盖了基类的函数。如果基类函数有 `final` 修饰,那派生类函数不能再覆盖该函数。

隐藏**(hide)也发生在继承关系中。如果派生类中定义的函数和基类中的某个函数同名,但签名不同,那基类的函数在派生类里会被隐藏。如果签名相同,但基类函数没有 `virtual` 修饰,那基类函数在派生类中也会被隐藏。

在上面 `Base` 和 `Derived` 类的例子里,`Derived` 类里的 `f(int)` 隐藏了 `Base` 类里的 `f(int)` 和 `f(double)`。也就是说,如果你写下下面这样的代码:

cpp

Derived d;

d.f(1); // OK,调用 Derived::f(int)

d.f(2.0); // 错误:Derived::f(int) 隐藏了 Base::f(double)

d.g(); // OK,调用 Base::g()

也就是说,在 `Derived` 类里,你可以调用 `f(int)` 和 `g()`,但 `f(double)` 被隐藏了,没法调用。

### 默认实参

在上面的例子里,`Base::g` 使用了默认实参。在派生类里,你不能“修改”基类函数的默认实参,但你可以“重新定义”基类函数的默认实参。如果基类函数的默认实参在派生类里不合适的话,这种做法可能是有用的。不过,这实际意味着基类和派生类里函数的签名不同,因此基类函数会在派生类里隐藏。一个简单的例子:

cpp

class Base {

public:

virtual void f(int i = 1) {

std::cout << "Base::f() " << i << std::endl;

}

};

class Derived : public Base {

public:

void f(int i = 2) override {

std::cout << "Derived::f() " << i << std::endl;

}

};

然后,如果我们写下如下代码:

cpp

Derived d;

Base& b = d;

b.f();

d.f();

输出将会是:

> `Derived::f() 1`

> `Derived::f() 2`

这里 `b` 和 `d` 指向的是同一个对象,但 `b.f()` 调用的是基类的默认实参,`d.f()` 调用的是子类的默认实参。这实际上可以理解成 `Base::f` 和 `Derived::f` 是两个不同的函数,只是它们有相同的名字和参数类型而已。

### 继承中的构造和析构

在继承关系里,当构造一个派生类的对象时,基类的构造函数会被自动调用。如果基类有多个构造函数,并且没有使用 `using` 引入到派生类里的话,编译器会根据派生类构造函数的初始化列表来判断使用哪个基类构造函数。如果派生类没有在初始化列表里提到基类,那编译器就会使用基类的默认构造函数。

Читайте также:  Камин в стиле минимализм в интерьере

反过来,当销毁一个派生类对象时,基类的析构函数也会被自动调用。

下面是一个简单的例子:

cpp

class Base {

public:

Base(int a) : a_(a) {}

int a_;

};

class Derived : public Base {

public:

Derived(int a) : Base(a) {}

};

在上面这个例子里,`Derived` 的构造函数必须使用 `Base(a)` 来初始化基类部分。如果 `Base` 有一个默认构造函数的话,那在 `Derived` 的构造函数的初始化列表里就可以不出现 `Base`。

跟构造函数不同,析构函数不允许有参数,每个类有且只有一个析构函数,因此情况就简单多了。

### 静态成员

基类中的静态成员也会被派生类继承。如果基类和派生类需要共享一个全局数据,可以考虑使用静态成员。

### 虚函数

在介绍覆盖时,我们已经提到了虚函数。事实上,虚函数是 C加加 面向对象的一个核心概念,是实现多态的关键。我们会在下一讲里专门讨论。

## 继承的使用

继承主要有两个用途:

1. 实现代码复用

2. 实现多态

实现多态我们留到下一讲再讲,本讲我们先专注于实现代码复用。

### 实现代码复用

在面向对象编程里,实现代码复用主要有两种方式:

1. 组合

2. 继承

组合的意思很简单,就是把要复用的对象作为类的一个成员来使用。比如,我们需要写一个类,来对某个数据进行分析,但分析前需要先对数据进行排序。排序的算法可能很复杂,我们不想写第二遍了。这时,如果有个排序类 `Sorter`,我们就可以使用组合的方式:

cpp

class Analysis {

public:

Analysis(Sorter sorter) : sorter_(sorter) {}

void analyse(std::vector& data) {

sorter_.sort(data);

// 进行数据分析

}

private:

Sorter sorter_;

};

这种组合的方式非常直观,也符合直觉。我们使用 `Analysis` 类时,需要构造一个 `Sorter` 对象作为参数传给 `Analysis`。`Analysis` 也可以使用 `Sorter` 的任意子类,只要 `Sorter` 有一个 `sort` 方法可以排序 `data` 就行––我们不需要在 `Analysis` 里关心 `Sorter` 的具体实现。

继承的方式我们前面已经提到了。通过继承,我们可以在派生类里直接使用基类的成员函数。但这种方式的问题是,继承是一种侵入性很强的方式。派生类会继承基类的所有成员,包括那些不希望被派生类使用的成员。另外,继承也是一种耦合度很高的方式。派生类和基类之间有着很强的依赖关系,基类的变化会影响到派生类。

因此,一般来说,组合是更好的代码复用方式。继承只有在需要实现多态时才是必要的。

### 实现多态

实现多态是继承的主要用途。我们下一讲再详细讨论。

### 私有继承

C加加 里有一种特殊的继承方式,叫做私有继承。私有继承的意思是,基类的所有成员在派生类里都是私有的。私有继承的语法是:

cpp

class Derived : private Base {

};

私有继承的用途是,派生类可以使用基类的成员,但派生类的用户不能使用基类的成员。换句话说,私有继承是一种实现继承,而不是接口继承。

私有继承的一个常见用途是实现“has-a”关系。比如,我们需要写一个类 `Car`,它有一个引擎 `Engine`。我们可以使用组合的方式:

cpp

class Car {

public:

Car() : engine_(Engine()) {}

void start() { engine_.start(); }

private:

Engine engine_;

};

但这样写的话,`Car` 的用户就不能直接使用 `Engine` 的成员了。如果 `Car` 的用户需要直接使用 `Engine` 的成员,我们可以使用私有继承:

cpp

class Car : private Engine {

public:

using Engine::start;

};

这样写的话,`Car` 的用户就可以直接使用 `Engine` 的 `start` 成员了。但 `Car` 的用户不能使用 `Engine` 的其他成员。

私有继承的另一个常见用途是实现“is-implemented-in-terms-of”关系。比如,我们需要写一个类 `Set`,它内部使用 `std::vector` 来存储数据。我们可以使用组合的方式:

cpp

class Set {

public:

void insert(int i) {

if (!contains(i)) {

data_.push_back(i);

}

}

bool contains(int i) {

return std::find(data_.begin(), data_.end(), i) != data_.end();

}

private:

std::vector data_;

};

但这样写的话,`Set` 的用户就不能直接使用 `std::vector` 的成员了。如果 `Set` 的用户需要直接使用 `std::vector` 的成员,我们可以使用私有继承:

cpp

class Set : private std::vector {

public:

using std::vector::push_back;

using std::vector::begin;

using std::vector::end;

void insert(int i) {

if (!contains(i)) {

push_back(i);

}

}

bool contains(int i) {

return std::find(begin(), end(), i) != end();

}

};

这样写的话,`Set` 的用户就可以直接使用 `std::vector` 的 `push_back`、`begin` 和 `end` 成员了。但 `Set` 的用户不能使用 `std::vector` 的其他成员。

### 保护继承

C加加 里还有一种特殊的继承方式,叫做保护继承。保护继承的意思是,基类的所有成员在派生类里都是保护的。保护继承的语法是:

cpp

class Derived : protected Base {

};

保护继承的用途是,派生类可以使用基类的成员,但派生类的用户不能使用基类的成员。换句话说,保护继承是一种实现继承,而不是接口继承。

保护继承的一个常见用途是实现“is-implemented-in-terms-of”关系。比如,我们需要写一个类 `Set`,它内部使用 `std::vector` 来存储数据。我们可以使用组合的方式:

cpp

class Set {

public:

void insert(int i) {

if (!contains(i)) {

data_.push_back(i);

}

}

bool contains(int i) {

return std::find(data_.begin(), data_.end(), i) != data_.end();

}

private:

std::vector data_;

};

但这样写的话,`Set` 的用户就不能直接使用 `std::vector` 的成员了。如果 `Set` 的用户需要直接使用 `std::vector` 的成员,我们可以使用保护继承:

Читайте также:  Как разметить столбы под забор

cpp

class Set : protected std::vector {

public:

using std::vector::push_back;

using std::vector::begin;

using std::vector::end;

void insert(int i) {

if (!contains(i)) {

push_back(i);

}

}

bool contains(int i) {

return std::find(begin(), end(), i) != end();

}

};

这样写的话,`Set` 的用户就可以直接使用 `std::vector` 的 `push_back`、`begin` 和 `end` 成员了。但 `Set` 的用户不能使用 `std::vector` 的其他成员。

### 多重继承

C加加 支持多重继承。多重继承的意思是,一个类可以从多个类继承。多重继承的语法是:

cpp

class Derived :

public Base1,

public Base2,

public Base3 {

};

多重继承的用途是,派生类可以使用多个基类的成员。但多重继承会带来很多复杂的麻烦,我们后面再具体讨论。

### 虚继承

C加加 里还有一种特殊的继承方式,叫做虚继承。虚继承的意思是,基类的所有成员在派生类里都是虚的。虚继承的语法是:

cpp

class Derived : virtual public Base {

};

虚继承的用途是,派生类可以使用基类的成员,但派生类的用户不能使用基类的成员。换句话说,虚继承是一种实现继承,而不是接口继承。

虚继承的一个常见用途是实现“is-implemented-in-terms-of”关系。比如,我们需要写一个类 `Set`,它内部使用 `std::vector` 来存储数据。我们可以使用组合的方式:

cpp

class Set {

public:

void insert(int i) {

if (!contains(i)) {

data_.push_back(i);

}

}

bool contains(int i) {

return std::find(data_.begin(), data_.end(), i) != data_.end();

}

private:

std::vector data_;

};

但这样写的话,`Set` 的用户就不能直接使用 `std::vector` 的成员了。如果 `Set` 的用户需要直接使用 `std::vector` 的成员,我们可以使用虚继承:

cpp

class Set : virtual public std::vector {

public:

using std::vector::push_back;

using std::vector::begin;

using std::vector::end;

void insert(int i) {

if (!contains(i)) {

push_back(i);

}

}

bool contains(int i) {

return std::find(begin(), end(), i) != end();

}

};

这样写的话,`Set` 的用户就可以直接使用 `std::vector` 的 `push_back`、`begin` 和 `end` 成员了。但 `Set` 的用户不能使用 `std::vector` 的其他成员。

## 小结

继承是面向对象编程语言中的一个重要机制。通过继承,一个对象可以使用另一个对象的代码,从而实现代码复用。

C加加 的继承机制有一个发展过程。在最早的 C 语言里,我们经常会写类似下面的代码:

cpp

struct employee {

int id;

const char* name;

int age;

double salary;

};

struct manager {

struct employee base;

const char group;

int group_size;

};

在这段代码里,`manager` 对象通过把 `employee` 对象放在第一个成员的位置,就自动继承了 `employee` 的全部成员。在需要 `employee` 的地方使用 `manager` 也是可以的,因为 `manager` 的第一个成员就是 `employee` 对象。从某种角度,这已经是一种继承机制了。

在 C加加 中,标准的选择是把继承直接作为一种语言机制来提供。上面的代码在 C加加 里可以简单地写成:

cpp

struct manager : employee {

const char group;

int group_size;

};

看起来更简洁了,不是?当然,上面的代码只是默认情况。我们通常还是应该写上 `public` 来表示继承关系的:

cpp

struct manager : public employee {

const char group;

int group_size;

};

继承的基本使用非常简单,不过,里面有一些细节需要注意。

作为一个例子,我们先定义一个 `Base` 类:

cpp

class Base {

public:

void f(int);

void f(double);

void g(int i = 10);

};

我们然后定义一个 `Derived` 类:

cpp

class Derived : public Base {

public:

void h();

void f(int);

};

`Derived` 类继承自 `Base` 类,并额外定义了一个 `h` 成员函数,同时重定义了一个 `f` 成员函数。注意,我们这儿说的是重定义,而不是重载。为了说清楚重载、覆盖和隐藏这些概念的区别,我们需要仔细分析一下。

重载(overload)发生在同一个类或名字空间里,函数名相同但参数类型不同的函数之间的关系。在上面的 `Base` 类里,`f(int)` 和 `f(double)` 就是一对重载函数。

覆盖**(override)一般发生在继承关系中。一个派生类中定义的函数如果和基类中定义的虚函数有相同的函数签名(函数名、参数类型、`const`/`volatile` 修饰符),那这个派生类的函数就覆盖了基类的函数。如果基类函数有 `final`

Оцените статью
Каскад Ремонт
Добавить комментарий