未继承的 C++ 受保护变量

Posted

技术标签:

【中文标题】未继承的 C++ 受保护变量【英文标题】:C++ Protected Variables Not Inherited 【发布时间】:2014-06-29 04:13:43 【问题描述】:

我编写了一些代码来计算 RSA 加密算法。该程序使用类和继承,因为我想为多个用户计算公钥和私钥。有一个父类rsa和子类public_keyprivate_key

编译下面的代码时,我得到了很多错误。所有这些都是关于派生类在其各自的构造函数中没有可用字段(请参见代码下方的错误消息)。但是,这些变量是在父类中使用protected 访问修饰符定义的,因此子类应该可以访问它们。

附注:我在两个子类中都有函数key,但我认为将它放在父类中一次会更好,对吗?

代码如下:

#include <iostream>
#include <math.h>

using namespace std;

class rsa

protected:
    int p, q, d, m, n, f, e, c, end, k;

public:
    rsa() : n(0), e(0), c(0), k(0), end(0), f(0)
     

    void set(int , int , int, int);

    int key()
    
        n = p * q;
        f = (p - 1) * (q - 1);

        for (k; end < 1; k++)
        
            if ((1 + k * f) % d == 0) 
            
                end = 2;
                e = (1 + k * f) / d;
            
        

        c = int(pow(m, e)) % n;

        return c;
    
;

void rsa::set(int p_, int q_, int d_, int m_)

    p = p_;
    q = q_;
    d = d_;
    m = m_;


class public_key : public rsa

public:
    public_key() : n(0), e(0), c(0), k(0), end(0), f(0)
     
;

class private_key : public rsa

public:
    private_key() : n(0), e(0), c(0), k(0), end(0), f(0)
     
;

int main()

    public_key usr1, usr2;
    private_key usr1r, usr2r;

    usr1.set(11, 5, 23, 9);
    usr2.set(13, 7, 97, 6);
    usr1r.set(17, 7, 51, 8);
    usr2r.set(11, 17, 51, 4);

    cout << "Public key of user 1: " << usr1.key() << endl;
    cout << "Public key o user 2: " << usr2.key() << endl;

    cin.get();

    return 0;

其中一个错误:

error: class ‘private_key’ does not have any field named ‘e’
   private_key () : n(0), e(0), c(0), k(0), end(0), f(0)  ;

所有其他错误都相同,但字段名称更改。

【问题讨论】:

请发布确切的错误和位置。 人们宁愿看到实际的错误消息,也不愿被告知您对错误消息的解释。 你不能像那样初始化基类的成员。 我已经编辑了问题,包含一个错误。我必须把所有的错误都写出来吗? @CaptainObvlious 初始化有什么问题?它正在编译没有错误,但那是函数键在两个派生类中的时候。 【参考方案1】:

该错误与rsa 类成员的访问级别无关。即使您声明这些成员public,您仍然会收到错误消息。问题是派生类的初始化列表仅在其自身上下文中运行,您无权访问基类成员。

但是,您可以在派生类构造函数的主体中访问基类成员(publicprotected)。例如:

class public_key : public rsa

public:
    public_key()
    
        n = 0;
        e = 0;
        c = 0;
        k = 0;
        end = 0;
        f = 0;
    
;

class private_key : public rsa

public:
    private_key()
    
        n = 0;
        e = 0;
        c = 0;
        k = 0;
        end = 0;
        f = 0;
    
;

虽然上面的代码使用 assignment 而不是 initialization,但它对原始类型(所有这些成员都是)执行完全相同的操作。

尽管如此,虽然上面的代码有效,但它是做你想做的事情的错误方式。您已经为类rsa 编写了一个构造函数,因此避免重复代码的一种方法是从初始化列表中调用您现有的构造函数。

class public_key : public rsa

public:
    public_key() : rsa()
     
;

class private_key : public rsa

public:
    private_key() : rsa()
     
;

但是请注意rsa() 是默认构造函数(因为它没有参数),因此它会被派生类的任何构造函数自动调用(除非您在初始化列表中指定了其他一些rsa 构造函数)。

class public_key : public rsa

public:
    public_key()
      // rsa() will be called automatically
;

class private_key : public rsa

public:
    private_key()
      // rsa() will be called automatically
;

但是现在您的派生类有空的默认构造函数,您甚至不需要它们(除非您打算添加更多逻辑)。

class public_key : public rsa

public:
    // rsa() will still be called automatically when declaring an instance of public_key
;

class private_key : public rsa

public:
    // rsa() will still be called automatically when declaring an instance of private_key 
;

关于key() 函数的旁注,如果key() 的实现在两个子类中相同,那么是的,您只需要在父类中使用一次。您应该始终避免代码重复,因此即使需要为每个子类自定义 key() 的一小部分,您最好在基类中编写一个虚拟函数,key() 可以作为计算的一部分调用。然后,在每个子类中,用任何必要的特化覆盖虚函数。因此所有共享代码都可以保留在父类key()函数中。

【讨论】:

好吧,不知道可以调用初始化列表中的构造函数。【参考方案2】:

根据 C++ 标准(12.6.2 初始化基和成员,第 #2 段)

除非 mem-initializer-id 命名构造函数的类,否则 构造函数类的非静态数据成员,或直接或 该类的虚拟基类,mem-initializer 格式不正确。

所以程序中派生类的 mem-initializers 格式不正确,编译器会发出错误。

它是应该初始化其数据成员的基类构造函数。

没有任何意义来定义类的构造函数,例如 public_key 如下方式

public_key () : n(0), e(0), c(0), k(0), end(0), f(0)  ;

因为一开始会调用基类的构造函数

rsa () : n(0), e(0), c(0), k(0), end(0), f(0) ;

它会初始化数据成员。

这样写就够了

rsa () 

rsa () = default;

【讨论】:

作为参考,你能提供一个链接到你得到这个的部分吗?谢谢。 @VladfromMoscow 因此,每当创建派生类的对象时,都会调用基类的构造函数,但它不会初始化该对象变量,除非它在构造函数中明确指定派生类!那么,基类的构造函数为什么不初始化派生类变量,除非明确声明,否则会被调用呢? @Mohamed Ahmed 你错了。基类的构造函数显式初始化 mem-initializer 中指定的数据成员。派生类的构造函数的 mem-initializer 中不需要指定它,因为无论如何都会被调用。 @Mohamed Ahmed 是的,你可以。我在我的帖子中展示了这一点。 @MohamedAhmed 是的,您可以简单地将派生类构造函数留空。事实上,如果它们是空的,则根本不需要它们。我已经更新了我的答案以包括所有这些。【参考方案3】:

应该是private_key() : rsa() ;

【讨论】:

您在技术上是正确的,但是您应该稍微详细说明您的答案:-) 我想但是在页面刷新后我看到了其他人的回应,所以没有必要复制。如果可以的话,我会删除我的答案。 您实际上可以在 cmets 开始之前通过单击帖子底部的链接来删除您自己的答案。在这种情况下,您不需要这样做,因为您的答案在技术上是正确的,只是缺少解释。只要你的答案没有错误或误导,就没有必要删除它。

以上是关于未继承的 C++ 受保护变量的主要内容,如果未能解决你的问题,请参考以下文章

带有受保护字段的微妙 C++ 继承错误

C ++未定义对已继承的受保护类成员的引用[重复]

C++ 为啥要使用公有、私有或受保护的继承?

公共/受保护/私有继承的问题

私有继承、公有继承和受保护继承之间的区别

私有继承、公有继承和受保护继承之间的区别