从派生类访问基类中的受保护成员

Posted

技术标签:

【中文标题】从派生类访问基类中的受保护成员【英文标题】:Accessing protected member in base class from a derived class 【发布时间】:2014-08-27 08:49:15 【问题描述】:

我有以下sn-p的代码:

const int DATE_LENGTH = 6;

class BaseClass 
    protected:
        int date[DATE_LENGTH];
        int year;
    public:
        BaseClass()
        BaseClass(int *d) 
            for (int i = 0; i < DATE_LENGTH; i++)  date[i] = d[i];
            year = 1900 + date[4] * 10 + date[5];
        
        void printYear() 
            cout << year << endl;
        
;

class DerivedClass : public BaseClass 
    public:
        DerivedClass() 
        void printYear() 
            cout << year << endl;
        
;

int main(int argc, char *argv[]) 
    int dob[] = 1, 6, 1, 0, 9, 0;
    BaseClass base(dob);
    base.printYear(); // prints 1990

    DerivedClass derived;
    derived.printYear(); // prints 1439156608

我无法理解为什么派生类中printYear() 的输出会输出垃圾。我是否遗漏了一些非常明显的东西?

任何帮助将不胜感激!

【问题讨论】:

你的默认构造函数不会初始化任何东西,所以你会得到内存中发生的任何东西。 @T.C.:这并不完全正确,基础子对象确实被初始化了。语言要求这种情况发生。只是选择了一个很差的初始化。 @RetiredNinja:这实际上不是你可以保证的。这是未定义的行为,你可能会从记忆中得到一些东西,或者披萨,或者丢掉工作。 你可以从未定义的行为中得到比萨吗?全速前进! @KerrekSB 你说得对,我要我的披萨! :) 【参考方案1】:

其他提供的答案仅处理部分问题,部分原因是 date 本身是 never 在 DerivedClass 默认构造函数中定义的当前提供,另一部分是 BaseClass 默认构造函数 still 没有为任一类变量(日期或年份)定义值。如果使用以下代码,取决于默认的日期和年份,DerivedClass 实际上不需要额外的更改。

#include <iostream>

using namespace std;

const int DATE_LENGTH = 6;

class BaseClass 
    protected:
        int date[DATE_LENGTH];
        int year;
    public:
        BaseClass()
        
            int date[] = 1, 6, 1, 0, 9, 0;
            year = 1900 + date[4] * 10 + date[5];
        
        BaseClass(int *d)
        
            for (int i = 0; i < DATE_LENGTH; i++)  date[i] = d[i];
            year = 1900 + date[4] * 10 + date[5];
        
        void printYear() 
            cout << year << endl;
        
;

class DerivedClass : public BaseClass 
    public:
        DerivedClass() 
        void printYear() 
            cout << year << endl;
        
;

int main(int argc, char *argv[])

    int dob[] = 1, 6, 1, 0, 9, 0;
    BaseClass base(dob);
    base.printYear(); // prints 1990

    DerivedClass derived;
    derived.printYear(); // prints 1439156608
    return 0;

应用程序输出

1990
1990

【讨论】:

【参考方案2】:

BaseClass的默认构造函数

BaseClass()

不初始化数据成员 dateyear

这个默认构造函数在创建对象派生时被DerivedClass类的默认构造函数调用

DerivedClass derived;

因此,这些数据成员具有任意值,并且您的程序具有未定义的行为。

通过以下方式更改派生类

class DerivedClass : public BaseClass 
    public:
        using BaseClass::BaseClass;
        DerivedClass() 
        void printYear() 
            cout << year << endl;
        
;

并创建派生的对象

DerivedClass derived( dob );

或者代替 using 声明,您可以自己在 DerivedClass 类中显式定义一个构造函数,该构造函数具有一个 int * 类型的参数,并调用基类的相应构造函数。例如

class DerivedClass : public BaseClass 
    public:
        DerivedClass() 
        DerivedClass( int *d ) : BaseClass( d ) 
        void printYear() 
            cout << year << endl;
        
;

【讨论】:

【参考方案3】:

您的程序有未定义的行为。您正在使用的DerivedClass 的默认构造函数不会初始化year 成员。

如果您想初始化基成员,可以通过调用适当的基构造函数或直接赋值来实现。

DerivedClass()  year = 1999; 

【讨论】:

你确定这是 UB 并且不能只是未指定的值吗? @Deduplicator,是的,year 未初始化,并对其执行了左值到右值的转换。

以上是关于从派生类访问基类中的受保护成员的主要内容,如果未能解决你的问题,请参考以下文章

C#:基类中的受保护方法;无法使用来自另一个类的派生类对象进行访问[重复]

在派生类中使用来自虚拟基类的受保护 ctor

在派生类中无法访问受保护的成员

为啥我不能访问静态多态派生类中的受保护成员?

C#访问派生类中的受保护成员[重复]

C++ 派生模板类:访问实例的受保护成员