涉及派生类成员函数

Posted

技术标签:

【中文标题】涉及派生类成员函数【英文标题】:Derived class member functions are involved 【发布时间】:2020-08-08 07:04:34 【问题描述】:

我从C++ Templates the Complete Guide 书中得到了一段代码: 在下面的程序中,我们创建了一个带有完美转发模板构造函数的Person 类 和另外两个成员函数(const拷贝构造函数,移动构造函数)

#include <utility>
#include <string>
#include <iostream>

class Person

  private:
    std::string name;
  public:
    // generic constructor for passed initial name:
    template<typename STR>
    explicit Person(STR&& n) : name(std::forward<STR>(n)) 
        std::cout << "TMPL-CONSTR for '" << name << "'\n";
    

    // copy and move constructor:
    Person (Person& p) : name(p.name) 
        std::cout << "COPY-CONSTR Person '" << name << "'\n";
    
    Person (Person const& p) : name(p.name) 
        std::cout << "COPY-CONSTR Person '" << name << "'\n";
    
    Person (Person&& p) : name(std::move(p.name)) 
        std::cout << "MOVE-CONSTR Person '" << name << "'\n";
    
;


int main()

  std::string s = "sname";
  Person p1(s);
  Person p2("tmp");
  Person p3(p1);            // Error
  Person p4(std::move(p1));

关于Person p3(p1); 行的错误,这本书说“根据重载解决规则”

template<typename STR>
Person(STR&& n)

“比复制构造更好匹配”

Person(const Person& p)

所以,如果我在 Person 内部再添加一个构造函数,如下所示:

Person (Person& p) : name(p.name) 
    std::cout << "COPY-CONSTR Person '" << name << "'\n";

错误应该消失。确实错误消失了,这是输出:

TMPL-CONSTR for 'sname'
TMPL-CONSTR for 'tmp'
COPY-CONSTR Person 'sname'              : this is due to `Person (Person& p)`
MOVE-CONSTR Person 'sname'

但书上也说,这只是部分解决方案,因为 Person 的 Derived 类的模板构造函数仍然是重载决议规则的更好匹配。

所以我也试着检查一下:

#include <utility>
#include <string>
#include <iostream>

class Person

  private:
    std::string name;
  public:
    // generic constructor for passed initial name:
    template<typename STR>
    explicit Person(STR&& n) : name(std::forward<STR>(n)) 
        std::cout << "TMPL-CONSTR for '" << name << "'\n";
    

    // copy and move constructor:
    Person (Person& p) : name(p.name) 
        std::cout << "COPY-CONSTR Person '" << name << "'\n";
    
    Person (Person const& p) : name(p.name) 
        std::cout << "COPY-CONSTR Person '" << name << "'\n";
    
    Person (Person&& p) : name(std::move(p.name)) 
        std::cout << "MOVE-CONSTR Person '" << name << "'\n";
    
;

#if 1 // or 0
class newPerson : public Person

  private:
    std::string name;
  public:
    // generic constructor for passed initial name:
    template<typename STR>
    explicit newPerson(STR&& n) : name(std::forward<STR>(n)) 
        std::cout << "TMPL-CONSTR for '" << name << "'\n";
    

    // copy and move constructor:
    newPerson (newPerson const& p) : name(p.name) 
        std::cout << "COPY-CONSTR Person '" << name << "'\n";
    
    newPerson (newPerson&& p) : name(std::move(p.name)) 
        std::cout << "MOVE-CONSTR Person '" << name << "'\n";
    
;
#endif

int main()

  std::string s = "sname";
  Person p1(s);
  Person p2("tmp");
  Person p3(p1);             // Error again
  Person p4(std::move(p1));

在这种情况下我正在粘贴 clang 错误(gcc 错误列表太大)

specialmemtmplMain.cpp:41:5: error: constructor for 'newPerson' must explicitly initialize the base class 'Person' which does not have a default constructor
    newPerson (newPerson const& p) : name(p.name) 
    ^
specialmemtmplMain.cpp:5:7: note: 'Person' declared here
class Person
      ^
specialmemtmplMain.cpp:44:5: error: constructor for 'newPerson' must explicitly initialize the base class 'Person' which does not have a default constructor
    newPerson (newPerson&& p) : name(std::move(p.name)) 
    ^
specialmemtmplMain.cpp:5:7: note: 'Person' declared here
class Person
      ^
2 errors generated.

所以,我的问题是,我没有实例化任何 newPerson 类。那为什么错误是指newPerson构造函数?这里到底发生了什么?

【问题讨论】:

【参考方案1】:

问题是派生类应该调用基类的构造函数之一。你没有显式调用构造函数,所以编译器会尝试隐式调用Person::Person()的默认构造函数,但是没有定义默认构造函数。

【讨论】:

以上是关于涉及派生类成员函数的主要内容,如果未能解决你的问题,请参考以下文章

类学习

C++派生类是不是可以从基类继承静态数据成员和静态成员函数?

为啥指向基类的派生类指针可以调用派生类成员函数? [复制]

指向派生类成员函数的指针,但不是派生(虚拟)函数

基类构造函数的派生类成员初始化

继承对基类私有数据成员的访问(在派生类中继承基类成员函数)