You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++子类重写父类方法遇链接错误:multiple definition与undefined reference

C++ 重写方法时的链接错误问题

问题背景

我想在geraet.cpp中重写elektronik.cpp里的schalten()方法,但执行链接命令g++ -o main main.o elektronik.o geraet.o时出现以下错误:

/usr/bin/ld: geraet.o: in function `schalten()':
geraet.cpp:(.text+0x0): multiple definition of `schalten()'; elektronik.o:elektronik.cpp:(.text+0x0): first defined here
/usr/bin/ld: main.o: in function `main':
main.cpp:(.text+0x23): undefined reference to `Geraet::schalten()'
collect2: error: ld returned 1 exit status

尝试在elektronik.h中将该方法设为virtual后,错误反而变多:

/usr/bin/ld: geraet.o: in function `schalten()':
geraet.cpp:(.text+0x0): multiple definition of `schalten()'; elektronik.o:elektronik.cpp:(.text+0x0): first defined here
/usr/bin/ld: main.o: warning: relocation against `_ZTV6Geraet' in read-only section `.text'
/usr/bin/ld: main.o: in function `main':
main.cpp:(.text+0x1e): undefined reference to `vtable for Geraet'
/usr/bin/ld: main.cpp:(.text+0x2e): undefined reference to `Geraet::schalten()'
/usr/bin/ld: warning: creating DT_TEXTREL in a PIE
collect2: error: ld returned 1 exit status

希望解答以下问题:

  1. 为什么我无法直接在子类中重写该方法?
  2. 为什么使用virtual方法无法解决这个问题?
  3. 为什么链接时会出现方法未定义的错误?

代码片段

main.cpp

#include "elektronik.h"
#include "geraet.h"
#include <iostream>

int main() {

    Geraet tool{};
    std::cout << tool.schalten() << std::endl;

    return 0;
}

elektronik.h

#pragma once

class Elektronik {
    public:
        bool schalten();
};

elektronik.cpp

#include "elektronik.h"

bool schalten() {
    return false;
}

geraet.h

#pragma once

class Geraet : public Elektronik {
    public:
        bool schalten();
};

geraet.cpp

#include "geraet.h"

bool schalten() {
    return true;
}

问题解答

1. 为什么无法直接在子类中重写该方法?

你根本没在重写方法——你的elektronik.cpp和geraet.cpp里定义的都是全局函数schalten(),而非类的成员函数。C++中定义类成员函数必须用类名::限定作用域,否则编译器会将其视为独立的全局函数,这就导致两个全局函数重名,触发链接器的multiple definition错误。

另外,即便你修正了作用域,父类方法未声明为virtual时,子类的同名方法只是隐藏父类方法,不是重写——调用时会根据变量的静态编译类型决定执行逻辑,而非动态运行类型,无法实现多态。

2. 为什么使用virtual无法解决问题?

加virtual只是让父类方法变成虚函数,但你依然没修正成员函数的定义问题——全局的schalten()仍然存在,重名冲突未解决。同时,当类包含虚函数时,编译器会生成虚表(vtable),但如果子类的虚函数没有正确定义(还是全局函数),编译器找不到Geraet::schalten()的实现,就会报undefined reference to vtable for Geraet和Geraet::schalten()未定义的错误。

3. 为什么链接时会出现方法未定义的错误?

因为链接器找不到Geraet::schalten()的真正实现——你在geraet.h里声明了这个成员函数,但geraet.cpp里写的是全局schalten(),不是Geraet::schalten()。链接器需要绑定成员函数的实现,找不到自然就会报未定义错误。


修复方案

把两个cpp文件里的函数改成类成员函数的正确定义方式:

修改后的 elektronik.cpp

#include "elektronik.h"

bool Elektronik::schalten() {
    return false;
}

修改后的 geraet.cpp

#include "geraet.h"

bool Geraet::schalten() {
    return true;
}

如果要实现真正的多态(重写),还需要把父类的schalten()声明为virtual,子类可以加override关键字明确重写:

修改后的 elektronik.h

#pragma once

class Elektronik {
    public:
        virtual bool schalten(); // 声明为虚函数
};

修改后的 geraet.h

#pragma once

class Geraet : public Elektronik {
    public:
        bool schalten() override; // 用override明确重写
};

这样编译链接就能正常通过,且用父类指针/引用指向子类对象时,会调用子类的实现,实现多态。


内容的提问来源于stack exchange,提问作者mabioo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 10:11:07