请考虑以下代码:
#include <iostream>
#include <string>
enum Type { T1, T2 };
class Base {
public:
std::string baseName;
Type type;
Base(const std::string& bn, Type t):
baseName(bn), type(t) {}
};
class Derived1 : public Base
{
public:
std::string dName;
int x = 10;
Derived1(const std::string& bn, const std::string& dn):
Base(bn, Type::T1), dName("Dervied1"+dn) {}
int getX(void) const { return x; }
};
class Derived2 : public Base
{
public:
std::string dName;
int y = 20;
Derived2(const std::string& bn, const std::string& dn):
Base(bn, Type::T2), dName("Derived2"+dn){}
int getY(void) const { return y; }
};
void func(Base& b)
{
if (b.type == Type::T1)
{
Derived1& d1 = static_cast<Derived1&>(b);
std::cout << d1.baseName << " " << d1.dName << " " << d1.getX();
std::cout << std::endl;
}
else
{
Derived2& d2 = static_cast<Derived2&>(b);
std::cout << d2.baseName << " " << d2.dName << " " << d2.getY();
}
};
int main(void)
{
Derived1 d1("Base", "foo");
func(d1);
Derived2 d2("Base", "foo");
func(d2);
}
要求是有一个函数可以接受基类值,然后根据&#34;类型&#34;派生实例,做一些不同的事情。我的问题是 - 这是正确的做事方式,还是我错过了一些重要的设计模式。我记得读过使用static_cast或dynamic_cast意味着设计本身存在一些错误。我理解,理想情况下,基类可以具有派生类实现的虚函数,并且在运行时它们可以进行多态调度。但是,在这种情况下,每个派生类中有两个特定于这些类的函数,即。 getX和getY。如何更改设计以使其更好,也许不使用演员?
谢谢!
答案 0 :(得分:2)
要求是拥有一个可以接受基类值的函数,然后根据派生实例的“类型”执行不同的操作。
这正是多态性的全部意义所在。但是你没有按照它的使用方式使用它。
我的问题是 - 这是正确的做事方式
没有
我错过了一些重要的设计模式。
通过完全删除 public async task<ActionResult> SendMail(object obj)
{
var result = await SendEmail(ToEmailAddresses,body,emailSubject)
return result
}
并在Type
中引入虚拟方法可以更好地处理这个问题。
我理解,理想情况下,基类可以具有派生类实现的虚函数,并且在运行时它们可以进行多态调度。
完全。
但是,在这种情况下,每个派生类中有两个特定于这些类的函数,即。 getX和getY。
所以?正确使用多态并不能阻止这种情况。
如何更改设计以使其更好,也许不使用演员?
正确使用多态。例如:
Base
然后通过移动公共代码使其更进一步,以便派生类可以共享它:
#include <iostream>
#include <string>
class Base
{
public:
std::string baseName;
Base(const std::string& bn):
baseName(bn) {}
virtual void doIt() = 0;
};
class Derived1 : public Base
{
public:
std::string dName;
int x = 10;
Derived1(const std::string& bn, const std::string& dn):
Base(bn), dName("Dervied1"+dn) {}
int getX(void) const { return x; }
void doIt() override
{
std::cout << baseName << " " << dName << " " << getX();
std::cout << std::endl;
}
};
class Derived2 : public Base
{
public:
std::string dName;
int y = 20;
Derived2(const std::string& bn, const std::string& dn):
Base(bn), dName("Derived2"+dn) {}
int getY(void) const { return y; }
void doIt() override
{
std::cout << baseName << " " << dName << " " << getY();
}
};
void func(Base& b)
{
b.doIt();
}
int main(void)
{
Derived1 d1("Base", "foo");
func(d1);
Derived2 d2("Base", "foo");
func(d2);
}
答案 1 :(得分:1)
如the other answer所述,如果您可以选择使用virtual
成员函数,则这是最佳使用方法。但是,有些情况下你没有那种奢侈品。在这种情况下,您可以根据派生类型的类型构建调度机制。
#include <iostream>
#include <string>
#include <map>
class Base {
public:
std::string baseName;
Base(const std::string& bn): baseName(bn) {}
virtual ~Base() {}
// Don't store type ID per instance.
// Make it a virtual function so derived classes
// can return the same value for each instance.
virtual int getTypeID() = 0;
// Helper function for derived classes to use so each
// derived class can have a unique type id associated
// with it. This eliminates the need for having an enum.
static int getNextTypeID();
{
static int typeID = 0;
return ++typeID;
}
};
class Derived1 : public Base
{
public:
std::string dName;
int x = 10;
Derived1(const std::string& bn,
const std::string& dn):
Base(bn), dName("Dervied1"+dn) {}
// get type ID for this class.
// Every instance of the class will return
// same value.
virtual int getTypeID()
{
return getTypeIDStatic();
}
// This is a crucial piece of function
// that allows type based dispatch mechanism to work.
static int getTypeIDStatic()
{
static int typeID = Base::getNextTypeID();
return typeID;
}
int getX(void) const { return x; }
};
class Derived2 : public Base
{
public:
std::string dName;
int y = 20;
Derived2(const std::string& bn,
const std::string& dn):
Base(bn), dName("Derived2"+dn){}
int getY(void) const { return y; }
virtual int getTypeID()
{
return getTypeIDStatic();
}
static int getTypeIDStatic()
{
static int typeID = Base::getNextTypeID();
return typeID;
}
};
// Define a function type.
using Function = void (*)(Base& b);
// Keep a registry of functions that can be called for
// different types derived from Base.
std::map<int, Function>& getRegisteredFunctionsMap()
{
static std::map<int, Function> functionsMap;
return functionsMap;
}
// Provide a mechanism to register functions for types
// derived from Base.
template <typename T>
void registerFunction(Function f)
{
getRegisteredFunctionsMap()[T::getTypeIDStatic()] = f;
}
void func(Base& b)
{
// Check whether there is a function base on the type of b.
std::map<int, Function>& functionsMap = getRegisteredFunctionsMap();
std::map<int, Function>::iterator iter = functionsMap.find(b.getTypeID());
if ( iter != functionsMap.end() )
{
// If yes, call it.
iter->second(b);
}
else
{
// No function to deal with the type.
// Deal with the situation.
}
};
// A function that can be called when the real type is Derived1.
void derived1Fun(Base& b)
{
// Assume that b is derived.
Derived1& d1 = dynamic_cast<Derived1&>(b);
// Now use d1.
std::cout << d1.baseName << " " << d1.dName << " " << d1.getX();
std::cout << std::endl;
}
// A function that can be called when the real type is Derived2.
void derived2Fun(Base& b)
{
// Assume that b is Derived2.
Derived2& d2 = dynamic_cast<Derived2&>(b);
// Now use d2.
std::cout << d2.baseName << " " << d2.dName << " " << d2.getY();
std::cout << std::endl;
}
int main(void)
{
// Register functions for Derived1 and Derived2.
registerFunction<Derived1>(derived1Fun);
registerFunction<Derived2>(derived2Fun);
// Make the function calls.
Derived1 d1("Base", "foo");
func(d1);
Derived2 d2("Base", "foo");
func(d2);
}
运行上述程序的输出:
Base Dervied1foo 10
Base Derived2foo 20