[c++] virtual operator= WTF
class derived : public base
{
public:
base& operator=(const base& rhs);
derived &operator=(const derived &rhs) {
data = rhs.data; return *this;
}
private:
int data;
};
Догадаешься, почему?
~/cpp/virtual_assign_test-build-desktop/../virtual_assign_test/main.cpp:24: error: undefined reference to `vtable for derived'
P.S. а вот если пустые скобки {} к присваиванию предка добавить, то собирается.
class base
{
public:
virtual base& operator=(const base& rhs) = 0;
};
class derived : public base
{
public:
base& operator=(const base& rhs);
private:
int data;
};
base& derived::operator =(const base& rhs)
{
data = dynamic_cast<const derived&>(rhs).data;
return *this;
}
int main(int , char *[])
{
derived d1,d2;
//d1 = d2;
d1 = dynamic_cast<base&>(d2);
return 0;
}
вы не должны этого хотеть же
class fbase
{
public:
virtual fbase& assign(const fbase& rhs) = 0;
};
class fderived : public fbase
{
public:
virtual fbase& assign(const fbase& rhs);
private:
int data;
};
fbase& fderived::assign(const fbase& rhs)
{
data = dynamic_cast<const fderived&>(rhs).data;
return *this;
}
int main(int , char *[])
{
fderived fd1, fd2;
fd1.assign(fd2);
return 0;
}
operator= равнее чем "обычные" функции?
operator= равнее чем "обычные" функции?Да бля.
Когда у тебя "только" base &derived::operator=(base const & у тебя еще есть неявный derived &derived::operator=(derived const &).
Из него и вызывается base &base::operator=(base const &). Поэтому компилятор и ругается.
Когда ты пишешь d1 = dynamic_cast(d2 вызывается derived::operator=(base const &).
operator= равнее в том смысле, что у него всегда есть как минимум один вариант, поэтому typecasting не происходит.
вот так работает. вопрос: как заставить компилер самому додуматься что d2 можно dynamic_cast в base& и вызывать реализованный оператор=?http://icu-project.org/docs/papers/cpp_report/the_assignment...
However, there’s another problem here. I remembered Taligent’s coding guidelines discouraging virtual assignment operators, so I went back to see why it recommended that. I wish I had done that before. It turns out Taligent’s guidelines weren’t hard and fast on the subject. Instead they point out that defining
virtual X& Y::operator=(const X& that);
won’t keep the compiler from defining
Y& Y::operator=(const Y& that);
In other words, an override of an inherited assignment operator doesn’t suppress the compiler-generated default assignment operator. You’d still have to do that manually by declaring it private and not giving it an implementation.
Instead, you’d have to define the default assignment operator to call the virtual one. In every class that inherits the virtual one.http://ideone.com/3JHps
Когда у тебя "только" base &derived::operator=(base const & у тебя еще есть неявный derived &derived::operator=(derived const &).
Из него и вызывается base &base::operator=(base const &). Поэтому компилятор и ругается.
так ведь даже если оно вызывается, я же прописал (перекрыл) его реализацию, хули оно говорит что я не прописал?
Instead, you’d have to define the default assignment operator to call the virtual one. In every class that inherits the virtual one.спасибо, я дотуда не дочитал, хотя эту страничку нагуглил :-)
я же прописал (перекрыл) его реализациюГде?
Где у тебя в программе написано base `&base base::operator=(base const &rhs)'?
undefined reference to `base::operator=(base const&)'
base& derived::operator =(const base& rhs)
{
if (this != &rhs)
{
data = dynamic_cast<const derived&>(rhs).data;
}
return *this;
}
разве место base::operator=(base const&) в vtable не должно указывать на перекрывающую его base& derived::operator=(const base&rhs) ?
разве место base::operator=(base const&) в vtable не должно указывать на перекрывающую его base& derived::operator=(const base&rhs) ?оно-то верно, но вызов оператора= невиртуальный происходит, судя по поведению
сгенерированный derived& derived::operator=(derived& o) вызывает base::operator=(o)
по-моему - странноватая логика поведения операторов. для невиртуальных может и удобно, а вот для виртуальных хрень получается.
разве место base::operator=(base const&) в vtable не должно указывать на перекрывающую его base& derived::operator=(const base&rhs) ?Я плюсов не знаю, поэтому объявление "class Derived: public Base {" можно метафорически представить так:
class Base {
virtual Base &operator=(const Base &) = 0; // undefined pure virtual method
};
class Derived {
Base __parent;
protected:
<Base-protected-method-1>
...
public:
<Base-public-method-1>(<Args>) {
return __parent.<public-method-1>(<Args>);
}
...
public again:
__implicit Derived &operator =(const Derived &rhs) {
__parent = rhs.__private; // link-time error: undefined method
<other-fields> = rhs.<other-fields>;
}
};
таблицу виртуальных методов забыл. в ней как раз-таки весь смысл.
Ну вот не в данном случае.
а в чем проблема? насколько я понимаю, derived::operator=(const base &) здесь вообще нигде не используется. вызывается derived::operator=(const derived & который, в свою очередь пытается вызвать base::operator=(const base & но не находит его
проблема в том, что виртуальная функция предка вызывается невиртуальным образом.
а с чего ты взял, что derived::operator=(const derived &) у тебя виртуальный?
он не виртуальный. но он вызывает виртуальную функцию предка base::operator=(const base& так вот он ее вызывает невиртуальным образом, иначе не было бы ошибки связывания.
а с чего ты взял, что он вызывает base::operator=(const base &) невиртуальным образом?
читай тред внимательно. можешь позапускать приведенные примеры и сделать выводы.
Оставить комментарий
elenangel
~/cpp/virtual_assign_test-build-desktop/../virtual_assign_test/main.cpp:8: error: undefined reference to `base::operator=(base const&)'