简体   繁体   English

在C ++库中创建对象(如std :: cout)

[英]Creating objects inside a C++ library (like std::cout)

I recently read somewhere that std::cout is an instance of the std::ostream class. 我最近在某处读到std::coutstd::ostream类的实例。 I wish to implement a similar kind of thing. 我希望实现类似的事情。 I make a class Animal and want to provide an instance of Animal class dog in the library itself like std::cout . 我创建了Animal类,并希望在库本身中提供std::cout这样的Animaldog的实例。 I am not sure how to do it but here's a code snippet which hopefully will give you an idea of what I'm trying to achieve. 我不确定该怎么做,但这是一个代码段,希望可以使您对我要实现的目标有所了解。

// lib.h

#ifndef LIB_H
#define LIB_H

#include <string>

class Animal {
public:
    Animal();
    std::string name;
};

Animal dog;
dog.name = "dog";
extern Animal dog;

#endif

// lib.cpp

#include "lib.h"

Animal::Animal() {}

Animal dog;
dog.name = "dog";

// main.cpp

#include "lib.h"
#include <iostream>

int main() {
    Animal my_dog = dog;
    std::cout << my_dog.name << std::endl;
    return 0;
}

This is the error I get when I try this code: 这是我尝试以下代码时遇到的错误:

lib.cpp:6:1: error: ‘dog’ does not name a type
 dog.name = "dog";

This kind of code may seem silly, but I still am looking for ways to implement this approach and not its alternatives. 这种代码看起来很愚蠢,但是我仍在寻找实现这种方法的方法,而不是替代方法。

EDIT : After several answers which are suggesting using inheritance or including the parameters in constructor. 编辑 :建议使用继承或在构造函数中包含参数的几个答案之后。 I will explain the actual problem that I am dealing with. 我将解释我正在处理的实际问题。

I am working on a motion planning library. 我正在研究运动计划库。 The library has an object called RoadmapPlanner . 该库有一个名为RoadmapPlanner的对象。 It is something similar to what is shown below 它类似于下面显示的内容

class RoadmapPlanner {
private:
    Graph g;
public:
    std::function<Graph(Workspace)> build_graph;
    std::function<Path(Graph,Point,Point) find_path;
    // and several others
}

Now I want to provide some pre-built motion planners to the user. 现在,我想向用户提供一些预先构建的运动计划器。 For example: I want to provide the voronoi_planner , which I want to implement by using the following syntax: 例如:我想提供voronoi_planner ,我想通过使用以下语法来实现:

RoadmapPlanner voronoi_planner;
voronoi_planner.build_graph = voronoi_graph_builder; // this describes what algorithms
voronoi_planner.graph_search = a_star_search;        // will be used internally
voronoi_planner.load_map("map_001.png");
voronoi_planner.run();

and so on... voronoi_graph_builder , a_star_search etc are functions that I have already written. 等等... voronoi_graph_buildera_star_search等是我已经编写的函数。 This thing works perfectly when I do this in the main function. 当我在main函数中执行此操作时,此功能可完美运行。 I want to provide several pre-built planners and also allow the user to build planner themselves by using the above syntax. 我想提供几个预先构建的计划器,并且还允许用户使用上述语法自行构建计划器。 The pre-built planners must be a part of the library so the user can use them by following the below syntax: 预构建的计划者必须是库的一部分,以便用户可以通过以下语法来使用它们:

RoadmapPlanner my_planner = voronoi_planner;
my_planner.search = rrt_search;

I hope this explains what I intend to do. 我希望这可以解释我打算做什么。

You cannot do the assignment of dog.name outside any function, you need to construct your Animal with its name directly: 您无法在任何函数之外进行dog.name的赋值,您需要直接使用其name构造Animal

// lib.hpp

class Animal {
public:
    Animal(std::string);
    std::string name;
};

extern Animal dog;

// lib.cpp

Animal::Animal(std::string name) : name(name) {}

Animal dog("dog");

If your type meets the requirements for aggregate initialization , you can omit the constructor: 如果您的类型符合集合初始化的要求,则可以省略构造函数:

// lib.hpp

class Animal {
public:
    std::string name;
};

extern Animal dog;

// lib.cpp

Animal dog = {"dog"};

Update after your edit: 编辑后更新:

In your edit, you define the variable dog in both lib.cpp and lib.hpp , this cannot work per the one definition rule : dog will be define in each of the .cpp file which include lib.hpp (and thus will be define multiple times). 在您的编辑中,您在lib.cpplib.hpp中都定义了dog变量,这不能按照一个定义规则工作dog将在每个包含lib.hpp.cpp文件中进行定义(因此将被定义多次)。

If you want to declare dog in your lib.hpp , you should use an anonymous namespace and not define it in lib.cpp . 如果要在lib.hpp声明dog ,则应使用匿名名称空间,而不要在lib.cpp定义它。

C++ does not allow statements to be placed in the global scope. C ++不允许将语句放在全局范围内。 The simplest way to solve this is to make Animal take its name in in its constructor so you can init your dog like so: 解决此问题的最简单方法是让Animal在其构造函数中使用其名称,以便您可以像这样初始化您的狗:

Animal dog("dog");

Also consider placing your static instance inside the Animal class itself, this way you get the added benefit of proper scope names. 还可以考虑将静态实例放置在Animal类本身内,这样您可以获得适当范围名称的额外好处。

// .h

class Animal {
public:
    Animal();
    std::string name;
    static Animal dog;
};

// .cpp
Animal Animal::dog("dog");
int i;

struct init_i
{
    init_i()::init_i() { i = 5; }
};

init_i _init;

i will be set to 5 before main() 我将在main()之前设置为5

What your looking for is class inheritance. 您需要的是类继承。 In your case it would look like this: 在您的情况下,它看起来像这样:

// lib.h

class Animal {
public:
    Animal();
    std::string name;
};

class Dog : public Animal {
public:
    Dog();
};

// lib.cpp

Animal::Animal() {}
Dog::Dog() { name = "dog"; }

// main.cpp

#include "lib.h"

int main() {
    Animal my_dog = Dog();
    std::cout << my_dog.name << std::endl;
    return 0;
}

I suggest you read about Object Oriented Programming Paradigms (Encapsulation, Inheritance Polymorphism) 我建议您阅读有关面向对象的编程范例(封装,继承多态)

Encapsulation means you will keep the attributes of your objects hidden from outside the class and use public method to assign or retrieve values from the object. 封装意味着您将对象的属性隐藏在类外部,并使用public方法从该对象分配或检索值。

Class Animal // parent class
{
    protected:
        std::string name;
    public:
        void setName(std::string n) { name = n; }
        std::string getName() { return name; }
}

Inheritance means allowing an object (child object) to get the same attributes form its parents. 继承意味着允许一个对象(子对象)从其父对象获得相同的属性。 In addition you can have additional attributes and methods unique to the child object. 此外,您可以具有子对象独有的其他属性和方法。

Class Dog: Animal   // child class inheriting parent class
{
    std::string sound;
    public:
        // now you can call getName and setName methods for Dog objects.
        void setSound(std::string s) { sound = s; }
        std::string getSound() { return sound; }
}

Usage: 用法:

Dog Askal;

Askal.setName("Bantay");
Askal.setSound("Woof");

Polymorphism allows the inherited method of a parent to change its behavior (code) according to its derived class. 多态性允许父级的继承方法根据其派生类更改其行为(代码)。 I leave this part for you to research since its not even required (yet) in your problem. 我将这一部分留给您研究,因为您的问题甚至还没有要求。

Reply to your EDIT: Why not use "enum" to list down different planners and include it in your library. 回复您的编辑:为什么不使用“枚举”列出不同的计划者并将其包括在您的库中。 Then use a switch statement to search what particular planner the user is looking for then execute the corresponding function (or algorithm) 然后使用switch语句搜索用户正在寻找的特定计划者,然后执行相应的功能(或算法)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM