gpt4 book ai didi

C++:使用模板时未覆盖函数

转载 作者:可可西里 更新时间:2023-11-01 17:46:08 26 4
gpt4 key购买 nike

我正处于为学校作业编写一个小型日历库的最后阶段,我遇到了一个意想不到且非常令人困惑的问题;当我引入模板时,我的赋值运算符没有被覆盖!

所以结构如下:我有一个抽象类 Date,主要是纯虚函数(包括赋值运算符),然后我有两个子类 GregorianJulian 实现了它的所有功能。最后,我为 Calendar 类编写了一个模板,其中包含今天的日期(以 GregorianJulian 对象的形式)和一些其他与这个特定问题无关的东西。

问题是当试图设置这个成员 today 时,我得到一个很长的链接器错误:

Error 4 error LNK2019: unresolved external symbol "public: virtual class lab2::Date & __thiscall lab2::Date::operator=(class lab2::Date const &)" (??4Date@lab2@@UAEAAV01@ABV01@@Z) referenced in function "public: class lab2::Gregorian & __thiscall lab2::Gregorian::operator=(class lab2::Gregorian const &)" (??4Gregorian@lab2@@QAEAAV01@ABV01@@Z) C:\Users...\test.obj Calendar

告诉我它在 Date 类中找不到函数 operator=(显然是因为它是纯虚拟的)。为什么它不使用任何被覆盖的? 它告诉我 Gregorian::operator= 正在尝试调用 Date::operator=?

这是出错的简化代码:

namespace cal_lib {
template <typename T>
class Calendar {
public:
Calendar() {
today = T(); // this yields the error
}
private:
T today;
};
}

这是 Gregorian.cpp 的片段:

namespace cal_lib {
class Gregorian : public Date {
public:
Gregorian();
virtual Gregorian& operator=(const Date& date);
virtual Date& add_year(int n = 1);
virtual Date& add_month(int n = 1);
};

// here I'm using Date's constructor to get the current date
Gregorian::Gregorian() {}

Gregorian& Gregorian::operator=(const Date& date) {
if (this != &date) {
// these member variables are specified as
// protected in Date
m_year = 1858;
m_month = 11;
m_day = 17;

add_year(date.mod_julian_day()/365);
add_month((date.mod_julian_day() - mod_julian_day())/31);
operator+=(date.mod_julian_day() - mod_julian_day());
}
}
}

Date 的(默认)构造函数只是将 m_yearm_monthm_day 的值设置为今天的日期:

Date::Date() {
time_t t;
time(&t);
struct tm* now = gmtime(&t);
m_year = now->tm_year + 1900;
m_month = now->tm_mon + 1;
m_day = now->tm_mday;
}

值得注意的是,这工作得很好:

Gregorian g;
Julian j;
g = j; // no problems here

Date* gp = new Gregorian();
Date* jp = new Julian();
*gp = *jp; // no problems here either

Calendar 类是这样实例化的:

using namespace cal_lib;

Calendar<Gregorian> cal;

我这里有什么非常明显的错误吗?

最佳答案

如果仔细阅读错误消息,您会注意到两件事,编译器正在尝试为以下内容找到定义:

Date& operator=(const Date&)

并且从以下定义中需要该符号:

Gregorian& operator=(const Gregorian&)

*那么那个运算符是怎么出现在你的程序中的呢? *

拷贝构造函数和赋值运算符比较特殊,它们总是会在程序中被声明。要么你提供一个声明,要么编译器会为你做。您提供了 Gregorian& Gregorian::operator=(const Date&),但这并没有从程序中删除 Gregorian& Gregorian::operator=(const Gregorian&)

当您尝试将一个 Gregorian 对象分配给另一个对象时,编译器会发现您的和隐式定义的两个重载,并且重载解析会发现隐式声明的赋值更匹配。这将以类似于以下的方式触发赋值运算符的定义:

T& operator=( T const & o ) {
Base::operator=(o); // for all bases
member=o.member; // for all members
}

您可以采取不同的措施来解决此问题。最简单的可能是在您的程序中定义 Date Date::operator=(const Date&)(将其保留为纯虚函数,但也提供定义)。这样,当编译器遇到两个派生类型相同的对象时,它就可以施展魔法,一切都会正常进行。您还可以通过在派生类型中强制分派(dispatch),将其用作分解基成员拷贝的实现的方法。

另一个需要更多努力的选项是为所有派生类型实际声明和定义赋值运算符。这里要写更多的代码,处理 Date 成员的代码需要复制,如果修改基类,则需要更新所有派生赋值运算符。 .我不会走那条路。

最后,一旦修复了编译器错误,请考虑您的赋值运算符的实现对于一般的 Date(实际上可能是 Gregorian)是否有意义日期)。想想如果你这样做会发生什么:

Gregorian d1 = ...; // some date
Gregorian d2 = d1; // same date
Date &d = d2;
d1 = d2; // What date does 'd1' represent??

请注意,如果您提供 Date::operator= 的定义并让编译器生成 Gregorian::operator=(Gregorian const&),此示例中的问题就会消失> 为你。

关于C++:使用模板时未覆盖函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13184510/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com