C++ 为什么我们需要C++;?
我刚刚学习了OOP类中的多态性,我很难理解抽象基类是如何有用的C++ 为什么我们需要C++;?,c++,oop,inheritance,abstract-class,C++,Oop,Inheritance,Abstract Class,我刚刚学习了OOP类中的多态性,我很难理解抽象基类是如何有用的 抽象类的用途是什么?定义抽象基类提供了什么,而不是通过在每个实际类中创建每个必需的函数来提供的?抽象类用于定义要实现的接口。见一些参考资料: 我有一只狗。抽象类狗用一种方法叫。我那只特别的狗会叫。其他狗则以不同的方式吠叫。因此,以抽象的方式定义狗是很有用的。当所有对象都需要从AbstractClass派生类型的功能,但不能在AbstractClass本身上合理地实现时,需要将抽象类AbstractClass作为基类 一个古老的、有点
抽象类的用途是什么?定义抽象基类提供了什么,而不是通过在每个实际类中创建每个必需的函数来提供的?抽象类用于定义要实现的接口。见一些参考资料:
我有一只狗。抽象类狗用一种方法叫。我那只特别的狗会叫。其他狗则以不同的方式吠叫。因此,以抽象的方式定义狗是很有用的。当所有对象都需要从
AbstractClass
派生类型的功能,但不能在AbstractClass
本身上合理地实现时,需要将抽象类AbstractClass
作为基类
一个古老的、有点人为的OO示例,它使用派生类汽车,摩托车。。。这里提供了一个很好的例子,假设您想要一个方法move()
-您可以实现汽车或摩托车的移动方式,但是车辆
不是以通用方式移动的,因此车辆::move()
必须是纯虚拟的,因此车辆
是抽象的
我们为什么不在每个类中创建每个必需的函数呢?(C++)
您必须在每个派生类中创建标记为abstract
的每个必要函数
若你们的问题是,为什么要在抽象类中创建抽象函数
它允许严格的限制
另请阅读抽象类允许编译时协议执行。这些协议定义了作为类族的一部分意味着什么
另一种方式是,抽象类是实现类必须履行的契约。如果他们不履行本合同,他们不能成为班级家庭的一部分,必须对他们进行修改以符合合同。提供的契约可以提供默认功能,但它也让子类定义更具体或不同的功能,同时仍在契约的范围内
对于小型项目来说,这似乎没有什么用处,但对于大型项目来说,它提供了一致性和结构,因为它通过抽象类契约提供了文档。这使得代码更易于维护,并且使每个子类都具有相同的协议,从而更容易使用和开发新的子类
abstract class dog
{
bark();
}
// function inside another module
dogbarking(dog obj)
{
dog.bark(); // function will call depend up on address inside the obj
}
// our class
ourclass: inherit dog
{
bark()
{
//body
}
}
main()
{
ourclass obj;
dogbarking(obj);
}
我们可以看到狗吠是在另一个模块中编写的函数。它只知道抽象类dog。即使它可以在我们的类中调用函数bark。在main函数中,我们创建了我们类的对象,并使用抽象类dog的引用对象将其传递给函数dogbarking。假设有两种方法显示字符串:
DisplayDialog(string s);
PrintToConsole(string s);
您需要编写一些可以在这两种方法之间切换的代码:
void foo(bool useDialogs) {
if (useDialogs) {
DisplayDialog("Hello, World!");
} else {
PrintToConsole("Hello, World!");
}
if (useDialogs) {
DisplayDialog("The result of 2 * 3 is ");
} else {
PrintToConsole("The result of 2 * 3 is ");
}
int i = 2 * 3;
string s = to_string(i);
if (useDialogs) {
DisplayDialog(s);
} else {
PrintToConsole(s);
}
}
此代码与用于显示字符串的特定方法紧密耦合。添加其他方法、更改方法的选择方式等将影响使用此方法的每段代码。这段代码与我们用来显示字符串的方法集紧密耦合
抽象基类是一种将使用某些功能的代码与实现该功能的代码分离的方法。它通过定义一个通用接口来实现这一点,该接口支持所有执行任务的各种方式
class AbstractStringDisplayer {
public:
virtual display(string s) = 0;
virtual ~AbstractStringDisplayer();
};
void foo(AbstractStringDisplayer *asd) {
asd->display("Hello, World!");
asd->display("The result of 2 * 3 is ");
int i = 2 * 3;
string s = to_string(i);
asd->display(s);
}
int main() {
AbstractStringDisplayer *asd = getStringDisplayerBasedOnUserPreferencesOrWhatever();
foo(asd);
}
使用AbstractStringDisplayer定义的接口,我们可以创建和使用我们想要的任意多个显示字符串的新方法,并且使用抽象接口的代码无需更改。抽象类的目的是为一组具体的子类定义一个通用协议。这在定义共享代码、抽象思想等的对象时非常有用
抽象类没有实例。抽象类必须至少有一个延迟方法(或函数)。为了在C++中实现这一点,声明了纯虚拟成员函数,但在抽象类中没有定义:
class MyClass {
virtual void pureVirtualFunction() = 0;
}
尝试实例化抽象类总是会导致编译器错误
“定义抽象基类提供了哪些未提供的功能
通过在每个实际类中创建每个必要的函数?”
这里的主要思想是代码重用和跨类的适当分区。在父类中定义一次函数比在多个子类中反复定义函数更有意义:
class A {
void func1();
virtual void func2() = 0;
}
class B : public A {
// inherits A's func1()
virtual void func2(); // Function defined in implementation file
}
class C : public A {
// inherits A's func1()
virtual void func2(); // Function defined in implementation file
}
拥有像“Dog”这样的抽象类和像“bark”这样的虚拟方法,允许所有从Dog继承的类以相同的方式调用它们的树皮代码,即使Beagle的树皮的实现方式与Collie的不同
如果没有公共抽象父级(或者至少有一个具有bark虚拟方法的公共父级),则很难执行以下操作:
有一种狗型的媒介,包括牧羊犬、比格犬、德国牧羊犬等,并让它们各自吠叫。对于一个包含牧羊犬、比格犬、德国牧羊犬的狗向量,要让它们都发出吠声,你所要做的就是在一个for循环中迭代,并在每个循环中调用吠声。否则,你必须有一个单独的牧羊犬载体,比格犬载体等
如果问题是“如果可以具体化,为什么要将狗抽象化,用可以覆盖的默认实现定义虚拟树皮?”,答案可能是这有时是可以接受的——但是,从设计角度来看,事实上,没有任何一种狗不是牧羊犬、小猎犬或其他品种或混血儿。因此,尽管它们都是狗,但实际上它们中没有一个是狗,也没有其他派生类。此外,由于狗的叫声因品种而异,因此不太可能有任何真正可接受的默认值
class mobileinternet
{
public:
virtual enableinternet()=0;//defines as virtual so that each class can overwrite
};
class 2gplan : public mobileinternet
{
private:
int providelowspeedinternet(); //logic to give less speed.
public:
void enableinternet(int) {
// implement logic
}
};
//similarly
class 3gplan : public enableinternet
{
private: high speed logic (different then both of the above)
public:
/* */
}