首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >C++不使用所需的构造函数。

C++不使用所需的构造函数。
EN

Stack Overflow用户
提问于 2020-05-30 20:31:00
回答 3查看 68关注 0票数 1

所以,在罗伯特·莱弗尔的“面向对象的C++编程,第4版”一书中,问题9-2的解决方案似乎存在一些问题。所以问题是,如果我想创建一个带有像Pstring = "This is a string"这样的语句的Pstring对象,那么Pstring构造函数将只调用String类中没有参数的构造函数,而不是使用一个char[]参数的第二个构造函数。有谁知道是什么原因造成了这种问题,并解决了这个问题?谢谢!

代码语言:javascript
运行
复制
#include <iostream>
#include <cstring>
using namespace std;
////////////////////////////////////////////////////////////////
class String                      //base class
{
protected:                     //Note: can't be private
    enum {
        SZ = 80
    };           //size of all String objects
    char str[SZ];               //holds a C-string
public:
    String()                    //constructor 0, no args
    {
        str[0] = '\0';
    }
    String(char s[])          //constructor 1, one arg
            {
        strcpy(str, s);
    }      //  convert string to String
    void display() const        //display the String
    {
        cout << str;
    }
    operator char*()            //conversion function
    {
        return str;
    }          //convert String to C-string
};
////////////////////////////////////////////////////////////////
class Pstring: public String     //derived class
{
public:
    Pstring(char s[]);        //constructor
};
//--------------------------------------------------------------
Pstring::Pstring(char s[])      //constructor for Pstring
        {
    if (strlen(s) > SZ - 1)           //if too long,
            {
        for (int j = 0; j < SZ - 1; j++) {  //copy the first SZ-1
            str[j] = s[j];           //characters "by hand"
            str[j] = '\0';
        }           //add the null character
    } else
        //not too long,
        String(s);                  //so construct normally
}
////////////////////////////////////////////////////////////////
int main() {                                        //define String
    String s1 = "This is a string"; // This works great
    s1.display();
    Pstring s2 = "This is a string"; // *** Here, nothing will be assigned to s2****
    s2.display();                    // *** Nothing will be printed here***
    return 0;
}
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-05-30 20:38:53

在函数参数中,T[] (在您的例子中,Tchar )实际上是一个T*

在C++中,字符串文本是一个const char[N]固定数组,它衰变为指向第一个元素的const char*指针。但是,没有任何构造函数接受这些类型中的任何一个作为参数。const char*不能给char*。需要将const添加到构造函数中:

String(const char s[])

Pstring(const char s[])

此外,在String(s)构造函数的主体中调用Pstring并不像您期望的那样使用基类String构造函数初始化Pstring对象。相反,它构建了一个临时的String对象,该对象立即超出作用域。Pstring对象不受此影响。

派生构造函数可以调用基类构造函数的唯一位置是在中。在您的示例中,没有这样的调用,因此编译器在进入派生构造函数的主体之前隐式调用基类默认(0-param)构造函数。这无助于您,因为您希望基类使用数据初始化str缓冲区。

可以这样做的一种方法是向String中添加另一个构造函数,该构造函数以用户定义的长度作为输入,然后从Pstring构造函数调用该构造函数,例如:

代码语言:javascript
运行
复制
String(const char s[], size_t len)
{
    len = std::min(len, SZ-1);
    memcpy(str, s, len);
    str[len] = '\0';
}

Pstring::Pstring(const char s[])
    : String(s, strlen(s))
{
}

注意,您的1-param String构造函数有一个缓冲区溢出等待发生,因为用户可以直接构造一个输入大于SZ字符长度的String对象。String构造函数应该使用strncpy()而不是strcpy()

代码语言:javascript
运行
复制
String(const char s[])
{
    strncpy(str, s, SZ);
    str[SZ-1] = '\0'; // in case s is >= SZ chars
}

这就使得1-param Pstring构造函数变得多余--特别是因为它一开始就没有正确地处理空终止符,因为终止符的分配需要在for循环之外,例如:

代码语言:javascript
运行
复制
Pstring::Pstring(const char s[])
{
    if (strlen(s) >= SZ)
    {
        for (int j = 0; j < SZ - 1; j++) {
            str[j] = s[j];
        }
        // alternatively: memcpy(str, sz, SZ-1);
        str[SZ-1] = '\0'; // <-- moved here
    }
    else
        strcpy(str, s);
}
票数 1
EN

Stack Overflow用户

发布于 2020-05-30 20:48:35

在此转换构造函数中

代码语言:javascript
运行
复制
Pstring::Pstring(char s[])      //constructor for Pstring
        {
    if (strlen(s) > SZ - 1)           //if too long,
            {
        for (int j = 0; j < SZ - 1; j++) {  //copy the first SZ-1
            str[j] = s[j];           //characters "by hand"
            str[j] = '\0';
        }           //add the null character
    } else
        //not too long,
        String(s);                  //so construct normally
}

首先调用类String的默认构造函数,然后将控件传递给类Pstring的构造函数。

因此,数据成员设置如下

代码语言:javascript
运行
复制
String()                    //constructor 0, no args
{
    str[0] = '\0';
}

作为参数,即字符串文本"This is a string" (顺便说一句,由于数组向指针的隐式转换而具有const char *类型),它的长度小于SZ,那么在构造函数体Pstring中,对数据成员str什么也不做。这句话

代码语言:javascript
运行
复制
String(s);

创建一个String类型的临时对象,该对象立即被删除。

你需要的至少是写

代码语言:javascript
运行
复制
strcpy( str, s );

而不是创建临时对象。

注意具有参数的构造函数应声明如下

代码语言:javascript
运行
复制
String( const char s[] );

代码语言:javascript
运行
复制
Pstring( const char s[]);

如果要使用字符串文本作为构造函数的参数。

你可以移动这个代码片段

代码语言:javascript
运行
复制
if (strlen(s) > SZ - 1)           //if too long,
        {
    for (int j = 0; j < SZ - 1; j++) {  //copy the first SZ-1
        str[j] = s[j];           //characters "by hand"
        str[j] = '\0';
    }           //add the null character
} else
    //not too long,
    String(s);                  //so construct normally

使用参数将构造函数Pstring转换为构造函数String,并将其替换为strncpy的一个调用,如

代码语言:javascript
运行
复制
strncpy( str, s, SZ - 1 );
str[SZ-1] = '\0';
票数 1
EN

Stack Overflow用户

发布于 2020-05-30 21:01:06

在C++,constructors aren't allowed to be called like this

代码语言:javascript
运行
复制
else
    //not too long,
    String(s);     

C++希望您使用它的初始化列表(有关一些示例,请参见the link above )。

如果要从子构造函数内部调用父类中的一部分构造,则可以使用受保护的方法:

代码语言:javascript
运行
复制
class String                      //base class
{
protected:
    void commonTask(char s[]) {
        // do something...
    }
public:
    String(char s[])
    {
        commonTask(s);
    }
};

class Pstring: public String
{
public:
    Pstring(char s[]) {        //constructor
        if(someCondition) {
            commonTask(s);
        }
    } 
};

我这里使用的是伪代码,但希望你能理解。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62108317

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档