C++ 通过映射从基 class 实现派生 class 并使用方法
C++ implementing derived class from base class by map and using methods from
我正面临问题,我想创建抽象 class 和 4 个子 classes。 Abstract class = Entry ,其他subclasses在代码中给出
class entry {
friend ostream &operator<<(ostream &os, const entry &obj);
private:
static constexpr char *def_info = "Undefind";
protected:
string desc;
int ID;
static int counter;
public:
entry() : entry(def_info) {}
entry(string input_s);
void setDesc(string);
string getDesc() const;
int getID() const;
virtual string getContents() const = 0;
virtual void displaying(ostream &os) const = 0;
virtual ~entry() = default;
};
int entry::counter = 0;
entry::entry(string input_s) :
desc{input_s} {
++counter;
ID = counter;
}
ostream &operator<<(ostream &os, const entry &obj) {
os << obj.getContents()<<endl;
obj.displaying(os);
return os;
}
void entry::setDesc(string input) {
desc = input;
}
string entry::getDesc() const {
return desc;
}
int entry::getID() const {
return ID;
}
//PhoneEntry extending the Entry with a phone number
class phone_entry :virtual public entry {
private:
static constexpr char *text = "Undefind";
static constexpr int def_no = 48000000000;
protected:
int phone_number;
public:
phone_entry(string input_s = text, int input = def_no) :
entry(input_s), phone_number(input) {}
virtual string getContents() const override {
ostringstream output;
output << "ID: " << ID << "\nD: " << desc << "\nPhone number : " << phone_number;
return output.str();
}
virtual ~phone_entry() = default;
};
//EmailEntry extending the Entry with an e-mail addres
class email_entry : virtual public entry {
private:
static constexpr char *def_info = "Undefind";
protected:
string email;
public:
email_entry(string des = def_info, string email_entry = def_info) :
entry(des), email{email_entry} {}
virtual string getContents() const override {
ostringstream output;
output << "ID: " << ID << "\nD: " << desc << "\nEmail : " << email;
return output.str();
}
virtual ~email_entry() = default;
};
//AddressEntry extending the Entry with an address containing a city, a street and a house number
class address_entry : virtual public entry {
private:
static constexpr char *def_info = "Undefind";
static constexpr int def_no = 0;
protected:
string city;
string street;
int house_number;
public:
address_entry(string des = def_info, string c = def_info, string s = def_info, int hn = def_no) :
entry{des}, city{c}, street{s}, house_number{hn} {}
virtual string getContents() const override {
ostringstream output;
output << "ID: " << ID << "\nD: " << desc << "\nCity: " << city << "\nStreet: " << street << "\nHouse number: "
<< house_number;
return output.str();
}
virtual ~address_entry() = default;
};
class contact_book : virtual public entry {
static constexpr char *def_info = "Undefind";
private:
map<string,entry *> contacts;
string nick_name;
public:
class error_mesg : public logic_error {
public:
error_mesg(const string message = "NULL") :
logic_error(message) {}
};
contact_book(string e = "undefind") :
entry{def_info},nick_name{e} {}
void add(string a , entry &content){
contacts.insert(make_pair(a,&content));
}
virtual void displaying(ostream &os) const override {
os << "TESTING";
}
};
我想使用 contact_book class 并使用映射容器通过使用 add 方法将键和值插入任何子 class 中,例如 ("cool", new phone_entry("NAME",000000)
它有两个参数,一个用于键,另一个必须连接到另一个 classes 所以我认为使用条目 obj 将完成我在成员中使用指针的工作,因为我想使用多态性。我也不知道如何使用 getContencts,它知道从哪个 subclass 调用。例如,他要求 main 看起来像这样:
ContactBook contacts(“My contacts”);
contacts.add(“Johny”, new PhoneEntry(“John Smith”, 100200300));
contacts.add(“Lisa”, new EmailEntry(“Lisa Wood”, “lisa@gmail.com”));
contacts.add(“Andy”, new AddressEntry(“Andrew Fox”, “Warsaw”, “Green St.”, 7));
cout << contacts;
//result (ordered):
//Andrew Fox: Warsaw, Green St. 7 (pos. 3)
//John Smith: phone 100200300 (pos. 1)
//Lisa Wood: e-mail lisa@gmail.com (pos. 2)
try {
cout << contacts[“Andy”].getContents() << endl;
//result:
//Andrew Fox: Warsaw, Green St. 7 (pos. 3)
能否请您帮助我了解如何实现它们并获得他想要的东西,以及将如何处理该添加方法以及主要功能中的新方法。
你不太清楚你的实际问题是什么——所以我假设你在获得整个通讯簿所需的输出时遇到了麻烦...
首先,还有一些其他问题:
让contact_book
继承entry
是没有意义的-书包含个条目,它不是一本。似乎您只继承了能够覆盖 displaying
函数才能将已经定义的 operator<<
用于 entry
class。但这是继承的糟糕理由。相反,您应该为您的通讯录提供单独的 operator<<
重载:
std::ostream& operator(std::ostream& s, contact_book const& cb); // coming to later
然后习惯于在适当的地方重用代码;我假设 getContents
应该输出与通过 operator<<
写入 std::cout
相同的字符串。好的,那我们从中获利:
std::string entry::getContents()
{
std::ostringstream s;
s << *this;
return s.str();
}
您不再需要(也不应该)将其虚拟化。
我个人会使用 displaying
函数的默认值(这不是一个很好的名称,不过,您应该更喜欢命令式形式 'display',也许更好:'printToStream' 或只是 'printTo'):
void entry::printTo(std::ostream& s)
{
// output members to s
}
然后您的继承 classes 可以重新使用它:
void phone_entry::printTo(std::ostream& s)
{
entry::printTo(s); // use parent's version first to print common data
// now append phone number to s...
}
不过,用户应该使用 operator<<
而不是 printTo
函数。保护它(甚至私有)可能是个好主意。
终于开始输出通讯录了:
std::ostream& operator(std::ostream& s, contact_book const& cb)
{
// you want to output every entry? then do so:
for(auto& e : cb.contacts)
{
s << *e.second << std::endl;
// ^^^^^^^ map entries are of type std::pair<key_type const, mapped_type>
// ^ you stored pointers, operator<< accepts reference
}
}
同样,您将重复使用已经编写的代码。
最后一点:您正在混合 classic 初始化(括号)和统一初始化(大括号),一次甚至在一行中 (email_contact
):
entry(des), email{email_entry}
我个人认为 UI 总的来说 有一些合理的推理,但是它在 C++ 中的实现方式被破坏了。还有很多其他问题,我的 'favourite' 一个是:
std::vector<int> v0{7}; // gives you a vector with 7 elements, all 0!!!
// with classic initialization:
std::vector<int> v1(7); // now clear, you WANT such a vector!
std::vector<int> v2({7}); // now clear, you want initializer list
您现在可以选择是否遵循我的推理(其他人选择 for UI 仍然可以从中获利),但无论您决定如何 – 请照做 在整个 file/project!
中始终如一地
我正面临问题,我想创建抽象 class 和 4 个子 classes。 Abstract class = Entry ,其他subclasses在代码中给出
class entry {
friend ostream &operator<<(ostream &os, const entry &obj);
private:
static constexpr char *def_info = "Undefind";
protected:
string desc;
int ID;
static int counter;
public:
entry() : entry(def_info) {}
entry(string input_s);
void setDesc(string);
string getDesc() const;
int getID() const;
virtual string getContents() const = 0;
virtual void displaying(ostream &os) const = 0;
virtual ~entry() = default;
};
int entry::counter = 0;
entry::entry(string input_s) :
desc{input_s} {
++counter;
ID = counter;
}
ostream &operator<<(ostream &os, const entry &obj) {
os << obj.getContents()<<endl;
obj.displaying(os);
return os;
}
void entry::setDesc(string input) {
desc = input;
}
string entry::getDesc() const {
return desc;
}
int entry::getID() const {
return ID;
}
//PhoneEntry extending the Entry with a phone number
class phone_entry :virtual public entry {
private:
static constexpr char *text = "Undefind";
static constexpr int def_no = 48000000000;
protected:
int phone_number;
public:
phone_entry(string input_s = text, int input = def_no) :
entry(input_s), phone_number(input) {}
virtual string getContents() const override {
ostringstream output;
output << "ID: " << ID << "\nD: " << desc << "\nPhone number : " << phone_number;
return output.str();
}
virtual ~phone_entry() = default;
};
//EmailEntry extending the Entry with an e-mail addres
class email_entry : virtual public entry {
private:
static constexpr char *def_info = "Undefind";
protected:
string email;
public:
email_entry(string des = def_info, string email_entry = def_info) :
entry(des), email{email_entry} {}
virtual string getContents() const override {
ostringstream output;
output << "ID: " << ID << "\nD: " << desc << "\nEmail : " << email;
return output.str();
}
virtual ~email_entry() = default;
};
//AddressEntry extending the Entry with an address containing a city, a street and a house number
class address_entry : virtual public entry {
private:
static constexpr char *def_info = "Undefind";
static constexpr int def_no = 0;
protected:
string city;
string street;
int house_number;
public:
address_entry(string des = def_info, string c = def_info, string s = def_info, int hn = def_no) :
entry{des}, city{c}, street{s}, house_number{hn} {}
virtual string getContents() const override {
ostringstream output;
output << "ID: " << ID << "\nD: " << desc << "\nCity: " << city << "\nStreet: " << street << "\nHouse number: "
<< house_number;
return output.str();
}
virtual ~address_entry() = default;
};
class contact_book : virtual public entry {
static constexpr char *def_info = "Undefind";
private:
map<string,entry *> contacts;
string nick_name;
public:
class error_mesg : public logic_error {
public:
error_mesg(const string message = "NULL") :
logic_error(message) {}
};
contact_book(string e = "undefind") :
entry{def_info},nick_name{e} {}
void add(string a , entry &content){
contacts.insert(make_pair(a,&content));
}
virtual void displaying(ostream &os) const override {
os << "TESTING";
}
};
我想使用 contact_book class 并使用映射容器通过使用 add 方法将键和值插入任何子 class 中,例如 ("cool", new phone_entry("NAME",000000)
它有两个参数,一个用于键,另一个必须连接到另一个 classes 所以我认为使用条目 obj 将完成我在成员中使用指针的工作,因为我想使用多态性。我也不知道如何使用 getContencts,它知道从哪个 subclass 调用。例如,他要求 main 看起来像这样:
ContactBook contacts(“My contacts”);
contacts.add(“Johny”, new PhoneEntry(“John Smith”, 100200300));
contacts.add(“Lisa”, new EmailEntry(“Lisa Wood”, “lisa@gmail.com”));
contacts.add(“Andy”, new AddressEntry(“Andrew Fox”, “Warsaw”, “Green St.”, 7));
cout << contacts;
//result (ordered):
//Andrew Fox: Warsaw, Green St. 7 (pos. 3)
//John Smith: phone 100200300 (pos. 1)
//Lisa Wood: e-mail lisa@gmail.com (pos. 2)
try {
cout << contacts[“Andy”].getContents() << endl;
//result:
//Andrew Fox: Warsaw, Green St. 7 (pos. 3)
能否请您帮助我了解如何实现它们并获得他想要的东西,以及将如何处理该添加方法以及主要功能中的新方法。
你不太清楚你的实际问题是什么——所以我假设你在获得整个通讯簿所需的输出时遇到了麻烦...
首先,还有一些其他问题:
让contact_book
继承entry
是没有意义的-书包含个条目,它不是一本。似乎您只继承了能够覆盖 displaying
函数才能将已经定义的 operator<<
用于 entry
class。但这是继承的糟糕理由。相反,您应该为您的通讯录提供单独的 operator<<
重载:
std::ostream& operator(std::ostream& s, contact_book const& cb); // coming to later
然后习惯于在适当的地方重用代码;我假设 getContents
应该输出与通过 operator<<
写入 std::cout
相同的字符串。好的,那我们从中获利:
std::string entry::getContents()
{
std::ostringstream s;
s << *this;
return s.str();
}
您不再需要(也不应该)将其虚拟化。
我个人会使用 displaying
函数的默认值(这不是一个很好的名称,不过,您应该更喜欢命令式形式 'display',也许更好:'printToStream' 或只是 'printTo'):
void entry::printTo(std::ostream& s)
{
// output members to s
}
然后您的继承 classes 可以重新使用它:
void phone_entry::printTo(std::ostream& s)
{
entry::printTo(s); // use parent's version first to print common data
// now append phone number to s...
}
不过,用户应该使用 operator<<
而不是 printTo
函数。保护它(甚至私有)可能是个好主意。
终于开始输出通讯录了:
std::ostream& operator(std::ostream& s, contact_book const& cb)
{
// you want to output every entry? then do so:
for(auto& e : cb.contacts)
{
s << *e.second << std::endl;
// ^^^^^^^ map entries are of type std::pair<key_type const, mapped_type>
// ^ you stored pointers, operator<< accepts reference
}
}
同样,您将重复使用已经编写的代码。
最后一点:您正在混合 classic 初始化(括号)和统一初始化(大括号),一次甚至在一行中 (email_contact
):
entry(des), email{email_entry}
我个人认为 UI 总的来说 有一些合理的推理,但是它在 C++ 中的实现方式被破坏了。还有很多其他问题,我的 'favourite' 一个是:
std::vector<int> v0{7}; // gives you a vector with 7 elements, all 0!!!
// with classic initialization:
std::vector<int> v1(7); // now clear, you WANT such a vector!
std::vector<int> v2({7}); // now clear, you want initializer list
您现在可以选择是否遵循我的推理(其他人选择 for UI 仍然可以从中获利),但无论您决定如何 – 请照做 在整个 file/project!
中始终如一地